Skip to content

rnhc1000/apiChallenge

Repository files navigation

API Aggregator Challenge

Goal: Another take-home challenge

Table of contents

Overview

This challenge delivers an application that consumes an external API endpoint. It is a RFC8288 compliant paginated endpoint to be consumed, returning a list of contacts and the pagination information via link header and should be built according to some specific requirements.

Requirements

  • The response from the endpoint should match the schema provided.

- Project structure and organization of your code: we want to see if your code follows good patterns, and separates concerns between controllers, services, and repositories.
- Capacity to follow good principles like Clean Code and SOLID.
- Capacity to use design patterns and knowledge about the chosen one(s) usage.
- Ability to consume other APIs and correctly handle pagination.
- Knowledge about the tools you decided to use.
- Ability to create smart tests to enhance your code quality.

Based on these, the app consumes services of another api -> Contacts API.


You can play with the app, visiting the link below after you build the app according to the instructions.

https://challenge.ferreiras.dev.br/swagger-ui/index.html
The app has been coded using Java 17, Spring Boot 3.3.4, Gradle, Javadoc, Spring Security, Spring JPA, Spring Webflux, OpenAPI, JUnit, Mockito, MySQL, Docker and others.
Take a look at the video below to understand how I faced the challenge.
Short Video


Project Structure

  • docs
    • javadocs
  • src
    • main
    • java
      • br.dev.ferreiras.challenge
        • contracts
        • config
        • controller
          • handlers
        • dto
        • entity
        • enums
        • repository
        • services
          • exceptions
    • resources
      • certs
    • test
      • java
        • br.dev.ferreiras.challenge
          • controller
          • service

Howto Build and Run

- MySQL Database: http://127.0.0.1:3306:challenge
- credentials available at classpath:db.properties
- profile active: dev or prod
- production socket:127.0.0.1:8097
- tweak a few knobs to get it up and running according to the instructions
  provided at classpath:dockerBuild.sh or just in case you want ro run
  locally go to {PWD}/challenge and run ./gradlew run, or check the video
  url shown below.

Screenshot

Links

Built with

My Skills

Code Snippet

import java.util.List;

/**
 * 
 * @author ricardo@ferreiras.dev.br
 * @version 1.1.10.23.01
 * @since 1.0
 *
 */

@RestController
@RequestMapping("api/v1")
public class ContactController {

    private final ContactService contactService;

    public ContactController(ContactService contactService) {
        this.contactService = contactService;
    }

    @Operation(summary = "Fetch 20 contacts per page")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "Get up to 20 contacts per page.",
                    content = {@Content(mediaType = "application/json",
                            schema = @Schema (implementation = ResponseContactsDto.class))}),
            @ApiResponse(responseCode = "400", description = "Bad Request",
                    content = {@Content(mediaType = "application/json")}),
            @ApiResponse(responseCode = "401", description = "Access Denied",
                    content = {@Content(mediaType = "application/json")}),
            @ApiResponse(responseCode = "403", description = "FORBIDDEN",
                    content = {@Content(mediaType = "application/json")}),
            @ApiResponse(responseCode = "404", description = "Resource not found!",
                    content = {@Content(mediaType = "application/json")})
    })
    @ResponseStatus(HttpStatus.OK)
    @GetMapping("/contacts")
    @PreAuthorize("hasAuthority('SCOPE_ROLE_ADMIN')")
    public Mono<ResponseContactsDto> getContacts(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "20") int size
    ) {

        return contactService.makeApiRequest()
                .bodyToMono(ResponseContactsDto.class);

    }
}

Continued development

  • Unit Tests - done
  • Subscriber Authentication - done
  • Spring JWT-OAuth2 - done
  • Records Pagination - done

Useful resources

Author

Ricardo Ferreira

- Portfolio

My Portfolio...