Gymterview
middle

Как создать REST-эндпоинт в плагине Jira DC?

REST-модуль плагина позволяет создавать API-эндпоинты, доступные по URL вида /rest/myapi/1.0/..., используя JAX-RS (Jersey).

Объявление в atlassian-plugin.xml

Пример
<rest key="my-rest-api" path="/myapi" version="1.0">
    <description>REST API моего плагина</description>
</rest>

REST-ресурс

Код ConfigResource
@Path("/config")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Named
public class ConfigResource {

    private final TaskConfigService configService;
    private final JiraAuthenticationContext authContext;
    private final PermissionManager permissionManager;

    @Inject
    public ConfigResource(TaskConfigService configService,
                          @ComponentImport JiraAuthenticationContext authContext,
                          @ComponentImport PermissionManager permissionManager) {
        this.configService = configService;
        this.authContext = authContext;
        this.permissionManager = permissionManager;
    }

    @GET
    @Path("/{id}")
    public Response getConfig(@PathParam("id") int id) {
        ApplicationUser user = authContext.getLoggedInUser();
        if (user == null) {
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }

        TaskConfig config = configService.getById(id);
        if (config == null) {
            return Response.status(Response.Status.NOT_FOUND)
                    .entity(new ErrorResponse("Config not found"))
                    .build();
        }

        return Response.ok(ConfigDto.from(config)).build();
    }

    @POST
    public Response createConfig(CreateConfigRequest request) {
        ApplicationUser user = authContext.getLoggedInUser();
        if (user == null) {
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }

        if (!permissionManager.hasPermission(GlobalPermissionKey.ADMINISTER, user)) {
            return Response.status(Response.Status.FORBIDDEN)
                    .entity(new ErrorResponse("Admin permission required"))
                    .build();
        }

        TaskConfig created = configService.create(
                request.getProjectKey(), request.getConfiguration());

        return Response.status(Response.Status.CREATED)
                .entity(ConfigDto.from(created))
                .build();
    }

    @DELETE
    @Path("/{id}")
    public Response deleteConfig(@PathParam("id") int id) {
        ApplicationUser user = authContext.getLoggedInUser();
        if (!permissionManager.hasPermission(GlobalPermissionKey.ADMINISTER, user)) {
            return Response.status(Response.Status.FORBIDDEN).build();
        }

        configService.delete(id);
        return Response.noContent().build();
    }
}

URL для вызова: GET https://jira.company.com/rest/myapi/1.0/config/42

Частые ошибки

  • Возвращение Entity (AO) напрямую вместо DTO — вызывает LazyLoading-ошибки и утечку данных
  • Забыть проверку прав — REST-эндпоинт доступен любому аутентифицированному пользователю
  • Использование @Autowired вместо @Inject в REST-ресурсе
  • CORS: Jira не добавляет CORS-заголовки по умолчанию — для внешних клиентов нужен servlet-filter

Как используется в 2026

  • REST-эндпоинты в плагинах — основной способ API-интеграции для DC
  • JAX-RS (Jersey) остаётся стандартом; переход на другие фреймворки невозможен из-за OSGi
  • Для CORS рекомендуется использовать Atlassian CORS Plugin или собственный фильтр

На собеседовании: покажите знание JAX-RS аннотаций (@Path, @GET, @POST, @Consumes, @Produces). Обязательно упомяните проверку аутентификации и авторизации в каждом эндпоинте — по умолчанию все эндпоинты требуют аутентификацию, @AnonymousAllowed — для открытых. Всегда возвращайте DTO, не AO-entity.