Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in
  • L LabraDoor
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 7
    • Issues 7
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
    • Requirements
  • Merge requests 2
    • Merge requests 2
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Container Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • EIPEIP
  • LabradorLabrador
  • LabraDoor
  • Merge requests
  • !71

Implement a more user friendly api

  • Review changes

  • Download
  • Email patches
  • Plain diff
Open Ruben Backx requested to merge more-user-friendly-api into development Aug 30, 2022
  • Overview 19
  • Commits 1
  • Pipelines 21
  • Changes 93

This MR aims to implement a more user friendly API to retrieve data.

The problem

Currently, when trying to retrieve nested data from core, multiple API controllers need to be injected. Take the following example of retrieving all submissions in an edition:

@Autowired
private EditionControllerApi editionApi;
@Autowired
private ModuleControllerApi moduleApi;
@Autowired
private AssignmentControllerApi assignmentApi;
// ...
@GetMapping("{id}/submissions") 
public String getAllSubmissions(@PathVariable Long id, Model model) {
    EditionDetailsDTO edition = editionApi.getEditionById(id).block();
    List<ModuleDetailsDTO> modules = moduleApi.getModulesByIds(edition.getModules().stream()
        .map(ModuleSummaryDTO::getId).toList()).collectList().block();
    List<AssignmentDetailsDTO> assignments = assignmentApi.getAssignmentsByIds(module.getAssignments().stream()
        .map(AssignmentSummaryDTO::getId).toList()).collectList().block();
    model.addAttribute("assignments", assignments);
    return "submissions";
}
<th:block th:each="assignment : ${assignments}">
    <div th:each="submission : ${assignment.submissions}"><!-- ... --></div>
</th:block>

Proposed solution

This MR implements a class for every entity in core with all data that is either present or can be lazily retrieved. The previous example can be written as follows:

@GetMapping("{id}/submissions") 
public String getAllSubmissions(@PathVariable Long id, Model model) {
    model.addAttribute("assignments", Edition.byId(id).getModules().bindLift(Module::getAssignments).get());
}

with idenitical html,

or:

<th:block th:each="module : ${@editionFinder.byId(editionId).getModules().get()}">
    <th:block th:each="assignments : ${module.getAssignments().get()}">
        <div th:each="submission : ${assignment.submissions}"><!-- ... --></div>
    </th:block>
</th:block>

where the body of the method is simply:

model.addAttribute("editionId", id);

Caching

All requested entities are cached per request, with the exception of PersonEntity, which is valid for a certain amount of time.

Extended Entities

In applications that require more data to be added to the core entities, the ExtendedEntityFinder and ExtendedEntityRepository can be used. For example, to define an edition with an additional hidden property, the following classes need to be created:

ExtendedEdition.java

@Entity
public ExtendedEdition {
    private Long id;
    private Boolean hidden;
}

ExtendedEditionView.java

@Data
@SuperBuilder
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public ExtendedEditionView extends Edition {
    private Boolean hidden;
}

ExtendedEditionRepository.java

public interface ExtendedEditionRepository extends ExtendedEntityRepository<ExtendedEdition, Long> {}

ExtendedEditionFinder.java

public class ExtendedEditionFinder extends ExtendedEntityFinder<Long, EditionDetailsDTO, Edition, ExtendedEdition, ExtendedEditionView, EditionCacheManager, EditionFinder, ExtendedEditionRepository> {
    @Override
    public void mapRepositoryData(ExtendedEditionView entity, ExtendedEdition databaseEntity) {
        entity.setHidden(databaseEntity.getHidden());
    }
}

ExtendedEditionView can then be used exactly like Edition.

Edited Aug 30, 2022 by Ruben Backx
Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: more-user-friendly-api