Skip to content

Latest commit

 

History

History
189 lines (149 loc) · 7.51 KB

File metadata and controls

189 lines (149 loc) · 7.51 KB

Contributing

Hello!

Coding Standards

Character Encoding

  • Use UTF-8 encoding for all source files
  • DO NOT use emojis in source code (scripts, Scala, Java, config files, etc.)
  • Emojis are only allowed in Markdown (.md) files - use them if you must.
  • Avoid non-ASCII characters in code unless absolutely necessary (e.g., comments in non-English languages)
  • Use plain ASCII alternatives in source code:
    • Instead of checkmark use [OK] or PASS
    • Instead of X mark use [FAIL] or ERROR
    • Instead of multiply use x
    • Instead of arrow use -> or <- Thank you for your interest in contributing to the Open Bank Project!

Pull requests

If submitting a pull request please read and sign our CLA first. In the first instance it is sufficient if you create a text file of the CLA with your name and include that in a git commit description.
If you end up making large changes to the source code, we might ask for a paper signed copy of your CLA sent by email to contact@tesobe.com

Git commit messages

Please structure git commit messages in a way as shown below:

  1. bugfix/Something
  2. feature/Something
  3. docfix/Something
  4. refactor/Something
  5. performance/Something
  6. test/Something
  7. enhancement/Something
  8. security/Something

Please also check if it also needs to be tagged (see below)

Git commit tags

  1. api_change <- if the requests/results of endpoints change or endpoints are added/deleted

Code comments

Please comment your code ! :-) Imagine an engineer is trying to fix a production issue: she is working on a tiny screen, via a dodgy mobile Internet connection, in a sandstorm - Your code is fresh in your mind. Your comments could help her!

Code style

When naming variables use strict camel case e.g. use myUrl not myURL. This is so we can automatically convert from camelCase to snake_case for JSON output.

Writing an API endpoint

    resourceDocs += ResourceDoc(
      getCustomersForUser,
      implementedInApiVersion,
      nameOf(getCustomersForUser),
      "GET",
      "/users/current/customers",
      "Get Customers for Current User",
      s"""Gets all Customers that are linked to a User.
        |
        |
        |${authenticationRequiredMessage(true)}
        |
        |""",
      emptyObjectJson,
      customerJsonV300,
      List(
        UserNotLoggedIn,
        UserCustomerLinksNotFoundForUser,
        UnknownError
      ),
      Catalogs(notCore, notPSD2, notOBWG),
      List(apiTagCustomer, apiTagUser))



    // This can be considered a reference new style endpoint.
    // This is a partial function. The lazy value should have a meaningful name.
    lazy val getCustomersForUser : OBPEndpoint = {
      // This defines the URL path and method (GET) for which this partial function will accept the call.
      case "users" :: "current" :: "customers" :: Nil JsonGet _ => {
        // We have the Call Context (cc) object (provided through the OBPEndpoint type)
        // The Call Context contains the authorisation headers etc.
        cc => {
          for {
            // Extract the user from the headers and get an updated callContext
            (Full(u), callContext) <- authorizedAccess(cc)
            // Now here is the business logic.
            // Get The customers related to a user. Process the resonse which might be an Exception
            (customers,callContext) <- Connector.connector.vend.getCustomersByUserIdFuture(u.userId, callContext) map {
              connectorEmptyResponse(_, callContext)
            }
          } yield {
            // Create the JSON to return. We also return the callContext
            (JSONFactory300.createCustomersJson(customers), HttpCode.`200`(callContext))
          }
        }
      }
    }

Recommended order of checks at an endpoint

    lazy val createProduct: OBPEndpoint = {
      case "banks" :: BankId(bankId) :: "products" :: ProductCode(productCode) :: Nil JsonPut json -> _ => {
        cc =>
          for {
            // 1. makes sure the user which attempts to use the endpoint is authorized
            (Full(u), callContext) <- authorizedAccess(cc)
            // 2. makes sure the user which attempts to use the endpoint is allowed to consume it
            _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext)
            // 3. checks the endpoint constraints
            (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
            failMsg = s"$InvalidJsonFormat The Json body should be the $PostPutProductJsonV310 "
            ...

Please note that that checks at an endpoint should be applied only in case an user is authorized and has privilege to consume the endpoint. Otherwise we can reveal sensitive data to the user. For instace if we reorder the checks in next way:

            // 1. makes sure the user which attempts to use the endpoint is authorized
            (Full(u), callContext) <- authorizedAccess(cc)
            // 3. checks the endpoint constraints
            (_, callContext) <- NewStyle.function.getBank(bankId, callContext)
            failMsg = s"$InvalidJsonFormat The Json body should be the $PostPutProductJsonV310 "
            (Full(u), callContext) <- authorizedAccess(cc)
            // 2. makes sure the user which attempts to use the endpoint is allowed to consume it
            _ <- NewStyle.function.hasAtLeastOneEntitlement(failMsg = createProductEntitlementsRequiredText)(bankId.value, u.userId, createProductEntitlements, callContext)

the user which cannot consume the endpoint still can check does some bank exist or not at that instance. It's not the issue if banks are public data at the instance but it wouldn't be the only business case all the time.

Writing tests

When you write a test for an endpoint please tag it with a version and the endpoint. An example of how to tag tests:

class FundsAvailableTest extends V310ServerSetup {

  /**
    * Test tags
    * Example: To run tests with tag "getPermissions":
    * 	mvn test -D tagsToInclude
    *
    *  This is made possible by the scalatest maven plugin
    */
  object VersionOfApi extends Tag(ApiVersion.v3_1_0.toString)
  object ApiEndpoint extends Tag(nameOf(Implementations3_1_0.checkFundsAvailable))

  feature("Check available funds v3.1.0 - Unauthorized access")
  {
    scenario("We will check available without user credentials", ApiEndpoint, VersionOfApi) {
      val bankId = randomBankId
      val bankAccount = randomPrivateAccount(bankId)
      val view = randomViewPermalink(bankId, bankAccount)
      When("We make a request v3.1.0")
      val request310 = (v3_1_0_Request / "banks" / bankId / "accounts" / bankAccount.bank_id / view / "funds-available").GET
      val response310 = makeGetRequest(request310)
      Then("We should get a 400")
      response310.code should equal(400)
      And("error should be " + UserNotLoggedIn)
      response310.body.extract[ErrorMessage].error should equal (UserNotLoggedIn)
    }
  }

}

Issues

If would like to report an issue or suggest any kind of improvement please use Github Issues.

Licenses

Open Bank Project API, API Explorer and Sofit are dual licenced under the AGPL and commercial licenses. Open Bank Project SDKs are licenced under Apache 2 or MIT style licences.

Please see the NOTICE for each project licence.

Setup and Tests

See the README for instructions on setup and running the tests :-)

Welcome!