-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Docs: Add Custom Code Guide #520
base: main
Are you sure you want to change the base?
Changes from 4 commits
63d3290
f766d8b
10acf27
bcf267b
331302d
a4dfac8
e636719
6d936b8
8fd6f3e
60dc5ab
196dbc6
face2c4
25516bd
2cbeaf2
a4bc821
14d9ca6
c86dfa5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,67 @@ | ||
--- | ||
id: add-custom-code | ||
title: How To Add Custom Code To Your Service | ||
sidebar_label: Add Custom Code To Your Service | ||
title: Adding Custom Code to Your Amplication Service | ||
sidebar_label: Adding Custom Code | ||
slug: /add-custom-code-to-your-service | ||
--- | ||
|
||
# How To Add Custom Code To Your Service | ||
# Adding Custom Code to Your Amplication Service | ||
|
||
While Amplication generates a robust, production-ready backend for your application, you'll often need to add custom business logic or additional functionality. This guide will walk you through the process of adding custom code to your Amplication-generated service while maintaining compatibility with future builds. | ||
While Amplication generates a robust, production-ready backend for your application, you'll often need to add custom business logic or additional functionality. This guide explains how Amplication manages custom code alongside generated code, and provides best practices for adding your own code to an Amplication-generated service. | ||
|
||
## Prerequisites | ||
|
||
Before you begin, make sure you have: | ||
Before you begin, make sure you know to: | ||
|
||
1. [Created your first service](/first-service/) | ||
1. [Create your first service](/first-service/) | ||
2. [Set up entities](/set-up-entities/) for your service | ||
3. [Configured roles and permissions](/configure-roles-and-permissions/) | ||
4. [Added plugins to your service](/add-plugins-service/) | ||
5. [Committed changes and built a new version](/commit-and-build-new-versions/) | ||
3. [Configure roles and permissions](/configure-roles-and-permissions/) | ||
4. [Add plugins to your service](/add-plugins-service/) | ||
5. [Commit changes and build a new version](/commit-and-build-new-versions/) | ||
|
||
## Understanding Custom Code in Amplication | ||
|
||
When adding custom code to your Amplication-generated service, it's important to understand how Amplication manages and preserves your changes: | ||
Amplication is designed to allow seamless integration of custom code with generated code through our [Smart Git Sync](/smart-git-sync) feature: | ||
|
||
1. Custom code is added to specific files that Amplication recognizes and preserves during rebuilds. | ||
2. You'll work directly in your git repository, making changes to the generated code. | ||
3. Amplication uses a folder structure that separates customizable and non-customizable code. | ||
4. The `base` folder contains files that should not be modified, as they will be overwritten by Amplication. | ||
5. Files outside the `base` folder can be safely customized and will be preserved across builds. | ||
1. All code in your Amplication project can be customized. | ||
2. Amplication uses a specific folder structure to manage custom and generated code. | ||
3. The `base` folder contains generated files that Amplication updates with each build. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Amplication can update the files in the base folder in each build, but also may update generated code in other files |
||
4. Files outside the `base` folder are intended for your custom code and are preserved across builds. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They may not be "preserved" as the generated code can be updated there. So I would say something like- |
||
5. Amplication uses [smart merging](/smart-git-sync) to update your project while preserving your custom code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should be more clear here and avoid using the word merging (as we merge nothing but suggest a PR that it can be merged). |
||
|
||
Let's walk through the process of adding custom code to implement a password reset feature for the User entity. | ||
:::note | ||
For more a more in-depth explanation, read [Understanding Custom Code in Amplication](/custom-code-overview/) | ||
::: | ||
|
||
## Step 1: Merge the Amplication Branch | ||
## How Amplication Handles Custom Code | ||
|
||
First, ensure that your local repository is up-to-date with the latest Amplication-generated code: | ||
Amplication preserves your custom code during updates: | ||
|
||
1. Open your terminal and navigate to your project's root directory. | ||
2. Switch to your main branch: | ||
```bash | ||
git checkout main | ||
``` | ||
3. Pull the latest changes: | ||
```bash | ||
git pull origin main | ||
``` | ||
4. Merge the `amplication` branch into your main branch: | ||
```bash | ||
git merge amplication | ||
``` | ||
5. Push the merged changes to your remote repository: | ||
```bash | ||
git push origin main | ||
``` | ||
1. Base files in the `base` folder are regenerated with each build. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The user will get updates in the base file only in case there are relevant changes. |
||
2. Non-base files (like `user.service.ts`) are preserved during updates. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again- that's NOT correct. That is exactly the code change that started this PR (amplication/amplication#8895). |
||
3. If necessary, changes to non-base files are required (e.g., removing references to a deleted plugin), Amplication will make these changes automatically while preserving your custom code. | ||
|
||
## Step 2: Create a New Branch for Custom Code | ||
## Adding Custom Code: A Simple Example | ||
|
||
Create a new branch from the main branch to make your custom code changes: | ||
Let's walk through a simple example of adding custom code to your service. | ||
|
||
### Step 1: Create A New Feature Branch | ||
|
||
Ensure that your local repository is up-to-date with the latest Amplication-generated code: | ||
|
||
```bash | ||
git checkout main && git merge amplication && git push origin main | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about the 'origin'- what is it? |
||
``` | ||
|
||
Next, create a new branch from the main branch to make your custom code changes: | ||
|
||
```bash | ||
git checkout -b feature/password-reset main | ||
git checkout -b feature/user-full-name | ||
``` | ||
|
||
## Step 3: Locate the Correct Files | ||
### Step 2: Locate the Correct Files | ||
|
||
Navigate to your service's `src` folder. You'll find a folder for each entity. In this case, we'll be working with the `user` folder: | ||
Navigate to your service's `src` folder and find the `user` folder: | ||
|
||
``` | ||
src | ||
|
@@ -78,169 +76,60 @@ src | |
└── user.service.ts | ||
``` | ||
|
||
We'll be modifying `user.service.ts` and `user.controller.ts` to add our custom password reset functionality. | ||
We'll be modifying `user.service.ts` to add our custom functionality. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we need to show also the content of the base file, and say that the API was generated in Amplication and now we are adding not the "functionality" but the business logic or such |
||
|
||
## Step 4: Add Custom Logic to the Service | ||
### Step 3: Add Custom Logic to the Service | ||
|
||
Open `src/user/user.service.ts`. This file extends the base service and is where we'll add our custom method. | ||
|
||
1. Add the necessary imports at the top of the file: | ||
|
||
```typescript | ||
import { Injectable } from "@nestjs/common"; | ||
import { PrismaService } from "nestjs-prisma"; | ||
import { UserServiceBase } from "./base/user.service.base"; | ||
import { PasswordService } from "../auth/password.service"; | ||
import { User } from "./base/User"; | ||
import { UserWhereUniqueInput } from "./base/UserWhereUniqueInput"; | ||
``` | ||
|
||
2. Add the custom `resetPassword` method to the `UserService` class: | ||
|
||
```typescript | ||
@Injectable() | ||
export class UserService extends UserServiceBase { | ||
constructor( | ||
protected readonly prisma: PrismaService, | ||
protected readonly passwordService: PasswordService | ||
) { | ||
super(prisma, passwordService); | ||
} | ||
|
||
async resetPassword(args: UserWhereUniqueInput): Promise<User> { | ||
const newPassword = Math.random().toString(36).slice(-8); // Generate a random password | ||
const hashedPassword = await this.passwordService.hashPassword(newPassword); | ||
|
||
const updatedUser = await this.prisma.user.update({ | ||
where: args, | ||
data: { | ||
password: hashedPassword | ||
} | ||
}); | ||
|
||
// In a real-world scenario, you'd want to send this password to the user securely | ||
console.log(`New password for user ${updatedUser.id}: ${newPassword}`); | ||
|
||
return updatedUser; | ||
async getUserFullName(userId: string): Promise<string> { | ||
const user = await this.findOne({ where: { id: userId } }); | ||
return `${user.firstName} ${user.lastName}`; | ||
} | ||
} | ||
``` | ||
|
||
## Step 5: Add a New Endpoint to the Controller | ||
|
||
Now, let's add a new endpoint to the User controller to expose our password reset functionality. Open `src/user/user.controller.ts`: | ||
|
||
1. Add the necessary imports at the top of the file: | ||
|
||
```typescript | ||
import * as common from "@nestjs/common"; | ||
import * as swagger from "@nestjs/swagger"; | ||
import * as nestAccessControl from "nest-access-control"; | ||
import { UserService } from "./user.service"; | ||
import { UserControllerBase } from "./base/user.controller.base"; | ||
import { User } from "./base/User"; | ||
import { UserWhereUniqueInput } from "./base/UserWhereUniqueInput"; | ||
import { AclValidateRequestInterceptor } from "../interceptors/aclValidateRequest.interceptor"; | ||
``` | ||
|
||
2. Add the new `resetPassword` endpoint to the `UserController` class: | ||
This example adds a simple method to get a user's full name. Note how it uses the `findOne` method from the base service. | ||
|
||
```typescript | ||
@swagger.ApiTags("users") | ||
@common.Controller("users") | ||
export class UserController extends UserControllerBase { | ||
constructor( | ||
protected readonly service: UserService, | ||
@nestAccessControl.InjectRolesBuilder() | ||
protected readonly rolesBuilder: nestAccessControl.RolesBuilder | ||
) { | ||
super(service, rolesBuilder); | ||
} | ||
|
||
@common.UseInterceptors(AclValidateRequestInterceptor) | ||
@common.Patch("/:id/reset-password") | ||
@nestAccessControl.UseRoles({ | ||
resource: "User", | ||
action: "update", | ||
possession: "own", | ||
}) | ||
@swagger.ApiOkResponse({ type: User }) | ||
@swagger.ApiNotFoundResponse({ type: errors.NotFoundException }) | ||
@swagger.ApiForbiddenResponse({ type: errors.ForbiddenException }) | ||
async resetPassword( | ||
@common.Param() params: UserWhereUniqueInput | ||
): Promise<User> { | ||
return this.service.resetPassword(params); | ||
} | ||
} | ||
``` | ||
|
||
## Step 6: Commit and Push Your Changes | ||
### Step 4: Push Your Changes | ||
|
||
After adding your custom code, commit the changes to your git repository: | ||
|
||
```bash | ||
git add . | ||
git commit -m "Added custom password reset functionality" | ||
git push origin feature/password-reset | ||
git commit -m "Added full name functionality" | ||
git push origin feature/user-full-name | ||
``` | ||
|
||
## Step 7: Create a Pull Request | ||
|
||
Go to your repository on GitHub (or your chosen git provider) and create a new pull request: | ||
|
||
1. Set the base branch to `main` | ||
2. Set the compare branch to `feature/password-reset` | ||
3. Give your pull request a descriptive title and description | ||
4. Create the pull request | ||
|
||
## Step 8: Merge the Pull Request | ||
|
||
After reviewing your changes, merge the pull request into the main branch. This step integrates your custom code with the main codebase. | ||
|
||
## Step 9: Rebuild Your Service in Amplication | ||
|
||
Now that you've added custom code to your repository and merged it into the main branch, you need to rebuild your service in Amplication to ensure everything works together: | ||
After going through any review process, merge the feature branch into your working branch: | ||
|
||
1. Go to your service in the Amplication web interface. | ||
2. Click on "Commit Changes & Build" in the right sidebar. | ||
3. In the commit message, write "Integrated custom password reset functionality". | ||
4. Click "Commit Changes & Build" to start the build process. | ||
|
||
Amplication will now rebuild your service, integrating your custom code with the generated code. | ||
|
||
## You're Done! | ||
|
||
Congratulations! You've successfully added custom code to implement a password reset feature in your Amplication-generated service. This custom logic will now be available through your API, allowing users to reset their passwords. | ||
|
||
## More Custom Code Examples | ||
|
||
Here are more examples of how to add custom code in different layers of your service. | ||
|
||
The purpose of these examples is to get familiar with the structure and responsibility of each of the components in the server. | ||
|
||
- **Example**: [How to add business logic to a service](/custom-code/business-logic/) | ||
- **Example**: [How to add an action to a REST API controller](/custom-code/controller-action/) | ||
- **Example**: [How to add a query to a GraphQL resolver](/custom-code/graphql-query/) | ||
```bash | ||
git checkout main && git merge feature/user-full-name && git push origin main | ||
``` | ||
|
||
## Best Practices for Custom Code | ||
|
||
When adding custom code to your Amplication service, keep these best practices in mind: | ||
|
||
1. Always add custom code to the non-base files (e.g., `user.service.ts` instead of `user.service.base.ts`). | ||
2. Use the types and interfaces generated by Amplication to ensure type safety. | ||
3. Leverage the existing services and utilities provided by Amplication (like `PasswordService` in this example). | ||
4. Document your custom code to make it easier for team members to understand and maintain. | ||
5. Always create a new branch for your custom code changes. | ||
6. Regularly merge the `amplication` branch into your main branch to stay up-to-date with Amplication-generated changes. | ||
1. Add custom code to non-base files (e.g., `user.service.ts` instead of `user.service.base.ts`). | ||
2. Use types and interfaces generated by Amplication to ensure type safety. | ||
3. Leverage existing services and utilities provided by Amplication. | ||
4. Document your custom code thoroughly. | ||
5. Create a new branch for significant custom code changes. | ||
6. Regularly pull and merge the latest Amplication-generated code from the `amplication` branch into your working branch. | ||
|
||
## Next Steps | ||
|
||
Now that you know how to add custom code to your Amplication service, you can extend its functionality in various ways: | ||
Now that you know how to add custom code to your Amplication service, you can: | ||
|
||
- Implement complex business logic specific to your application | ||
- Add custom API endpoints for specialized operations | ||
- Extend generated services with additional methods | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using Amplication to add APIs and DTOs? |
||
- Create custom utilities and helpers | ||
- Integrate with external services or APIs | ||
- Implement advanced validation and data processing | ||
|
||
Amplication is designed to be flexible, allowing you to leverage its powerful code generation while still giving you the freedom to customize your service as needed. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,19 +8,19 @@ pagination_next: getting-started/add-custom-code | |
|
||
# Understanding Custom Code in Amplication | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure this is the best title that reflects the content of the page. The page is not about understanding custom code, but more about the relations / separation between custom code and generated code in Amplication There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding to this comment- |
||
|
||
This page provides an overview of how custom code works in Amplication and our vision for seamless integration between generated and custom code. | ||
|
||
## The Vision | ||
|
||
Our vision is to empower you to add custom code to your server while maintaining the ability to use Amplication for updating your data model, changing permissions, adding roles, and more. Amplication achieves this by merging changes via our [Smart Git Sync](/smart-git-sync/) feature, based on pre-defined policies that allow you to add and update services, controllers, resolvers, and more without losing the link to Amplication. This approach gives you the freedom and power of custom code while saving time on repetitive tasks. | ||
Amplication allows seamless integration of custom code with generated code, empowering you to add custom business logic while continuing to use Amplication for updating your data model, permissions, roles, and more. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add APIs, and integrations as well |
||
|
||
## How It Works | ||
|
||
Your Amplication-generated application is structured to allow easy and maintainable customization, with a clear separation between customizable and non-customizable code. | ||
Amplication uses a specific folder structure and smart merging using [Smart Git Sync](/smart-git-sync) to manage custom and generated code: | ||
|
||
1. All code in your Amplication project can be customized. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comments in the other file regarding this part |
||
2. Amplication generates a folder structure that separates base files from non-base files intended for custom code. | ||
3. Updates to your Amplication configuration regenerate base files while preserving your custom code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again- it's not accurate. All the code and files are regenerated (but we don't need to say it), and we create a PR with the required code updates |
||
|
||
### Folder Structure | ||
|
||
Each entity has a dedicated folder under the 'src' folder, containing all necessary modules and files: | ||
Each entity has a dedicated folder under the `src` folder: | ||
|
||
``` | ||
└── src | ||
|
@@ -32,9 +32,9 @@ Each entity has a dedicated folder under the 'src' folder, containing all necess | |
|
||
Within each entity folder, files are split into two groups: | ||
|
||
1. **Base files**: Located in the 'base' folder, these are automatically generated by Amplication with every change. **They should not be altered as they will be overwritten with each new build**. | ||
1. **Base files**: Located in the 'base' folder, these are automatically generated by Amplication with every build. While these can be modified, changes to these files may be lost in subsequent builds. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "While these can be modified, changes to these files may be lost in subsequent builds." - That's incorrect and let's avoid saying so! We are not losing any code of the user....! |
||
|
||
2. **Non-base Customizable files**: These inherit from the base files and can be safely customized with your custom code. They reside directly in the entity folder. | ||
2. **Non-base files**: These inherit from the base files and are intended for your custom code. They reside directly in the entity folder and your custom code is preserved across builds. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The custom code is always preserved and respected (whenever it's added) |
||
|
||
``` | ||
src | ||
|
@@ -48,31 +48,39 @@ src | |
└── ... | ||
``` | ||
|
||
Amplication may still update the non-base files that include your custom code in certain circumstances. These updates are limited to changes necessary for preventing errors and ensuring the project can build correctly. For example, if you remove a plugin that was previously used in your service, Amplication might update the non-base files to remove references to the removed plugin, thus preventing build errors. | ||
|
||
This approach allows Amplication to maintain the integrity of your project structure while still preserving your custom code to the greatest extent possible. | ||
## Smart Git Sync | ||
|
||
## Amplication's Approach to Custom Code | ||
Amplication uses [Smart Git Sync](/smart-git-sync/) to merge changes, preserving your custom code while updating generated parts. This feature: | ||
|
||
Amplication is designed to preserve your custom code while allowing for continuous updates to the generated code. Here's how it works: | ||
1. Regenerates base files with each build. | ||
2. Preserves non-base files containing your custom code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again- all custom code is preserved... |
||
3. Makes necessary updates to non-base files (e.g., removing references to deleted plugins) while maintaining your custom code. | ||
|
||
1. **Initial Generation**: Amplication generates both base and customizable files for each module. | ||
## Best Practices for Custom Code | ||
|
||
2. **Subsequent Updates**: When you make changes in Amplication (e.g., updating the data model), it regenerates the base files and updates the customizable files as needed. | ||
1. Add custom code to non-base files (e.g., `user.service.ts` instead of `user.service.base.ts`). | ||
2. Use types and interfaces generated by Amplication to ensure type safety. | ||
3. Leverage existing services and utilities provided by Amplication. | ||
4. Document your custom code thoroughly. | ||
5. Create a new branch for significant custom code changes. | ||
6. Regularly pull and merge the latest Amplication-generated code into your working branch. | ||
|
||
3. **Smart Merging**: Amplication uses [Smart Git Sync](/smart-git-sync/) to merge changes, preserving your custom code while updating the generated parts. | ||
## Handling Conflicts | ||
|
||
4. **Conflict Resolution**: If conflicts arise, Amplication provides clear indications and allows you to resolve them manually. | ||
While Amplication strives to preserve your custom code, conflicts may arise, especially with significant changes to your data model or entity structure. If conflicts occur: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's emphasize that the conflict resolution should take place on 'amplication' branch, and then- merge the result to the main branch |
||
|
||
This approach allows you to freely add custom business logic, new endpoints, or any other customizations while still benefiting from Amplication's code generation and updates. | ||
1. Amplication will provide clear indications of the conflicting areas. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the known git mechanism |
||
2. You may need to manually resolve these conflicts, merging your custom code with the updated generated code. | ||
3. After resolving conflicts, thoroughly test your application to ensure everything works as expected. | ||
|
||
## Considerations | ||
|
||
- Customizing the client application (Admin UI) code is not currently supported within Amplication's regeneration process. If you need to customize the client, it's recommended to clone the entire **Admin** folder to a separate repository. | ||
- While Amplication strives to maintain compatibility, major changes to your data model or entity structure may require manual updates to your custom code. | ||
- While all code can be customized, we recommend focusing custom code in the non-base files for easier maintenance. | ||
- Major changes to your data model or entity structure may require manual updates to your custom code. | ||
- Client-side customization (Admin UI) is supported, but changes may not be automatically merged in future builds. Consider maintaining a separate repository for extensive client-side customizations. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove it. I don't think it adds value here |
||
|
||
## Next Steps | ||
|
||
Now that you understand how custom code works in Amplication, you're ready to start adding your own business logic and customizations. For a step-by-step guide on how to add custom code to your service, check out our [How To Add Custom Code To Your Service](/add-custom-code-to-your-service) guide. | ||
Now that you understand how custom code works in Amplication, you're ready to start adding your own business logic and customizations. For a step-by-step guide, check out our [How To Add Custom Code To Your Service](/add-custom-code-to-your-service) guide. | ||
|
||
Happy coding! | ||
Happy coding! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of saying this- we can say that custom code can be added to all files or such.