diff --git a/corporate-connections/README.md b/corporate-connections/README.md index b3821f2..f098a16 100644 --- a/corporate-connections/README.md +++ b/corporate-connections/README.md @@ -2,18 +2,17 @@ Build an API for looking up corporate connections using the Companies House api. -The GET endpoint should take an officerId and return a JSON array of connected officerIds. -To do this, the backend must find their companies, then find all other officers of those companies. - #### Companies House API E.g. for officerId `aEdQfmEjiBuB7tLwOP_Wfg-JA-8`, this curl request returns their companies: `curl -XGET -u : https://api.company-information.service.gov.uk/officers/aEdQfmEjiBuB7tLwOP_Wfg-JA-8/appointments` -And for companyId `03114488`, this curl request returns its officers: +And for companyNumber `03114488`, this curl request returns its officers: `curl -XGET -u : https://api.company-information.service.gov.uk/company/03114488/officers` +[API Docs](https://developer-specs.company-information.service.gov.uk/companies-house-public-data-api/reference). + #### Running the webserver Use the API_KEY environment variable to set the Companies House api key: @@ -30,3 +29,33 @@ webserver-project$ API_KEY=my-api-key sbt (Server started, use Enter to stop and go back to the console...) ``` + +### Task 1: proxy appointments data for an officer +Implement the `/officer/:id/appointmentsProxy` endpoint. + +Pass through the unaltered Companies House API appointments response for an officerId. + +E.g. for officerId `aEdQfmEjiBuB7tLwOP_Wfg-JA-8`: `https://api.company-information.service.gov.uk/officers/aEdQfmEjiBuB7tLwOP_Wfg-JA-8/appointments` + +Build on the `CompaniesHouseService` class in the `services` package for talking to the Companies House API. + +### Task 2: return companyNumbers for an officer +Implement the `/officer/:officerId/appointments` endpoint. + +Use Circe to decode the Companies House response into Scala case classes. Use the `OfficerAppointmentResponse` model in `models/CompaniesHouseModels.scala`. + +Then return just the list of companyNumbers, as a JSON array. + +### Task 3: return officer names for a given companyNumber +Implement the `/company/:companyNumber/officers` endpoint. + +E.g. for companyNumber 03114488: `https://api.company-information.service.gov.uk/company/03114488/officers` + +Use Circe to decode the Companies House response into Scala case classes. Use the `CompanyOfficersResponse` model in `models/CompaniesHouseModels.scala`. + +### Task 4: +Implement the `/officer/:officerId/connections` endpoint. + +It should take an officerId and return a JSON array of connected officer names. + +To do this, the backend must find their companies, then find all other officers of those companies. diff --git a/corporate-connections/app/controllers/CompaniesHouseController.scala b/corporate-connections/app/controllers/CompaniesHouseController.scala index a2f14bd..0f75e48 100644 --- a/corporate-connections/app/controllers/CompaniesHouseController.scala +++ b/corporate-connections/app/controllers/CompaniesHouseController.scala @@ -5,14 +5,8 @@ import services.CompaniesHouseService import scala.concurrent.{ExecutionContext, Future} -class CompaniesHouseController(components: ControllerComponents, companiesHouseService: CompaniesHouseService)(implicit ec: ExecutionContext) extends AbstractController(components) { - def getAppointments(officerId: String) = Action.async { - Future { - Ok(s"hello $officerId") - } - } - - def getConnections(officerId: String) = Action.async { +class CompaniesHouseController(components: ControllerComponents)(implicit ec: ExecutionContext) extends AbstractController(components) { + def getAppointmentsProxy(officerId: String) = Action.async { Future { Ok(s"hello $officerId") } diff --git a/corporate-connections/app/models/CompaniesHouseModels.scala b/corporate-connections/app/models/CompaniesHouseModels.scala index 59786c6..d3e10d3 100644 --- a/corporate-connections/app/models/CompaniesHouseModels.scala +++ b/corporate-connections/app/models/CompaniesHouseModels.scala @@ -1,7 +1,7 @@ package models -case class CompanyLink(company: String) -case class Appointment(officer_role: String, links: CompanyLink) +case class AppointedTo(company_name: String, company_number: String, company_status: String) +case class Appointment(officer_role: String, appointed_to: AppointedTo) case class OfficerAppointmentResponse(items: List[Appointment]) object OfficerAppointmentResponse { diff --git a/corporate-connections/app/services/CompaniesHouseService.scala b/corporate-connections/app/services/CompaniesHouseService.scala index 42a577f..044c9c7 100644 --- a/corporate-connections/app/services/CompaniesHouseService.scala +++ b/corporate-connections/app/services/CompaniesHouseService.scala @@ -4,23 +4,13 @@ import play.api.libs.ws.{WSAuthScheme, WSClient} import scala.concurrent.{ExecutionContext, Future} -class CompaniesHouseService(wsClient: WSClient, apiKey: String)(implicit ec: ExecutionContext) { +class CompaniesHouseService(wsClient: WSClient)(implicit ec: ExecutionContext) { - def getAppointmentsRaw(officerId: String): Future[String] = { + private def fetch(url: String): Future[String] = { wsClient - .url("TODO") - .withAuth(apiKey,"", WSAuthScheme.BASIC) + .url(url) + .withAuth("API KEY GOES HERE","", WSAuthScheme.BASIC) .get - .map(response => "TODO") - } - - // TODO - what should this return? - def getCompanies(officerId: String): Unit = { - // TODO - get list of companies linked to officer - } - - // TODO - what should this return? - def getOfficers(companyId: String): Unit = { - // TODO - get list of officers linked to company + .map(response => response.body) } } diff --git a/corporate-connections/app/wiring/AppComponents.scala b/corporate-connections/app/wiring/AppComponents.scala index fd68a9e..1be8d26 100644 --- a/corporate-connections/app/wiring/AppComponents.scala +++ b/corporate-connections/app/wiring/AppComponents.scala @@ -9,11 +9,11 @@ import router.Routes import services.CompaniesHouseService class AppComponents(context: Context) extends BuiltInComponentsFromContext(context) with NoHttpFiltersComponents with AssetsComponents with AhcWSComponents { - val apiKey = System.getenv("API_KEY") - val companiesHouseService = new CompaniesHouseService(wsClient, apiKey) + val apiKey = System.getenv("API_KEY") // TODO - use the api key + val companiesHouseService = new CompaniesHouseService(wsClient) // TODO - use the companiesHouseService override lazy val router: Router = new Routes( httpErrorHandler, - new CompaniesHouseController(controllerComponents, companiesHouseService) + new CompaniesHouseController(controllerComponents) ) } diff --git a/corporate-connections/conf/routes b/corporate-connections/conf/routes index 4af88c4..8d465fb 100644 --- a/corporate-connections/conf/routes +++ b/corporate-connections/conf/routes @@ -1,2 +1,11 @@ -GET /officer/:id/appointments controllers.CompaniesHouseController.getAppointments(id: String) -GET /officer/:id/connections controllers.CompaniesHouseController.getConnections(id: String) +# Task 1: proxy appointments data for an officer (i.e. just pass through Companies House API response unaltered) +GET /officer/:officerId/appointmentsProxy controllers.CompaniesHouseController.getAppointmentsProxy(officerId: String) + +# Task 2: return companyNumbers for an officer +#GET /officer/:officerId/appointments controllers.CompaniesHouseController.getAppointments(officerId: String) + +# Task 3: return officer names for a given companyNumber +#GET /company/:companyNumber/officers controllers.CompaniesHouseController.getOfficers(companyNumber: String) + +# Task 4: return connected officer names for a given officerId +#GET /officer/:officerId/connections controllers.CompaniesHouseController.getConnections(officerId: String)