Skip to content
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

Better structured project #19

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions corporate-connections/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <api-key>: 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 <api-key>: 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:

Expand All @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
4 changes: 2 additions & 2 deletions corporate-connections/app/models/CompaniesHouseModels.scala
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is much more comprehensible now that we're using the more descriptive bit of the API

case class OfficerAppointmentResponse(items: List[Appointment])

object OfficerAppointmentResponse {
Expand Down
20 changes: 5 additions & 15 deletions corporate-connections/app/services/CompaniesHouseService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
6 changes: 3 additions & 3 deletions corporate-connections/app/wiring/AppComponents.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
}
13 changes: 11 additions & 2 deletions corporate-connections/conf/routes
Original file line number Diff line number Diff line change
@@ -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)