diff --git a/src/components/pages/__tests__/__snapshots__/api-docs.tsx.snap b/src/components/pages/__tests__/__snapshots__/api-docs.tsx.snap index b7d67c0d8e..da5c483d85 100644 --- a/src/components/pages/__tests__/__snapshots__/api-docs.tsx.snap +++ b/src/components/pages/__tests__/__snapshots__/api-docs.tsx.snap @@ -11,7 +11,662 @@ exports[`ApiDocs should match a snapshot 1`] = ` hasBackground={true} hasPadding={true} > -

+

+ Foundations API +

+

+ Overview +

+

+ The Foundations API is organised around + + + REST + + + with all resources accessible using standard + + HTTP methods + + and returning predictable + + response codes + + . All request and response bodies, including errors, are encoded in + + JSON + + and served over + + + HTTPS TLS v1.1+ + + to ensure data privacy and security. +

+

+ Our API resources are secured and require an + + + authorization JWT bearer token + + to be submitted as part of requests sent to protected endpoints. For more information how our APIs are secured, please see + + + Authorization + + . +

+

+ Alternatively, our + + Developer Sandbox + + provides a quick start experience to quickly get to grips with the platform and start developing. +

+

+ REST +

+
+ HTTP Methods +
+

+ Foundation APIs present a uniform interface for performing CRUD (create, retrieve, update, delete) operations. Each endpoint adheres to REST guidelines to map the correct verb to the operation being performed. Our APIs support the following HTTP methods: +

+ +
+ Response status codes +
+

+ Foundation APIs use standardised HTTP status codes to indicate whether a request has been successful or has resulted in an error. Below is a listing of the codes our APIs may return and their meaning: +

+
application/json.", + "title": "Bad request", + }, + Object { + "code": "401", + "description": "The provided authentication credentials are incorrect or not present. Generally, this is due to the lack of an \\"Authorization\\" header", + "title": "Unauthorized", + }, + Object { + "code": "403", + "description": "The provided authentication credentials do not provide the request with sufficient scope to fulfill the request.", + "title": "Forbidden", + }, + Object { + "code": "404", + "description": "The requested resource was not found", + "title": "Not found", + }, + Object { + "code": "422", + "description": "A validation error has occured. The error response body will provide additional information on the failure(s).", + "title": "Unprocessable entity", + }, + Object { + "code": "429", + "description": "The request was not accepted because the application has exceeded the rate limit. See Rate Limit for an overview of this mechanism", + "title": "Too many requests", + }, + Object { + "code": "500", + "description": "The request was not accepted because the application has exceeded the rate limit. See Rate Limit for an overview of this mechanism", + "title": "Too many requests", + }, + ] + } + loading={false} + /> +

+ Authorization +

+

+ The Foundation platform uses + + OpenID Connect + + (OIDC) as it's Authentication protocol, based on the OAuth 2.0 specification. +

+

+ Our authentication mechanisms allow you to quickly build apps on top of our platform and provide a seamless authentication experience for your end users. +

+
+ Registering your application +
+

+ Your application must be registered with our Marketplace before it can interact with data, functionality and assets provided by the Foundations API. For more information on how to register your application, see our Marketplace documentation. +

+

+ As part of creating your application, you'll be required to choose the + + + scopes + + that you application requires. Scopes govern the actions that your application can perform against our services. Each endpoint will detail the scopes that an application must be granted in order to interact with it. +

+

+ Once your application has been successfully registered, you will be provided with a unique application id which is required to interact with our authorization services. +

+
+ Client installation +
+

+ Once your application submission has been approved by Reapit, it will appear as a listing in our Marketplace. Reapit clients will then be able to interact with your application's details and potentially choose to install it. +

+

+ As part of the installation process, clients are required to agree to the scopes that your application requires before your application becomes accessible to end users. Applications cannot interact with client data or assets without prior approval from the client. +

+

+ Once installed, an application can access Foundation services on an end users behalf. The recommended way to achieve this is to use one of our Client Libraries, however you can interact directly with our APIs as detailed below. +

+
+ Create an authorization code +
+

+ To create an OAuth + + authorization code + + , direct users to the URL documented below where they'll be prompted to enter their credentials. The clientId parameter is required and provided during the Marketplace app registration process. +

+

+ + GET https://foundations.reapit.com/oauth/authorize?clientId=xxxxxxxxxxxxxxxx + +

+

+ Upon success, the service will direct back to your application with an authorization code provided as a query string. +

+

+ + https://application.company.com/?code=xxxxxxxxxxxxxxxx + +

+
+ Exchange code for tokens +
+

+ If your application has successfully guided the end user through the OAuth flow and obtained an authorization code, you need to send it along with the client id issued to your application during Marketplace registration to the following endpoint: +

+

+

+          
+            POST https://foundations.reapit.com/oauth/access_token
+            
+  {
+    "clientId" : "xxxxxxxxxxxxxxxx",
+    "code" : "xxxxxxxxxxxxxxx"
+  }
+              
+          
+        
+

+

+ Issuing a request with a valid authorization code and client id will provide a response in the following format: +

+

+

+          
+            Content-Type: application/json
+            
+{
+  "id_token" : "xxxxxxxxxxxxxx"
+  "refresh_token" : "xxxxxxxxxxxxxx",
+  "access_token" : "xxxxxxxxxxxxxx",
+  "expires_in" : 3600,
+}
+              
+          
+        
+

+
+
+ Create a request +
+

+ The access token must then be sent in the Authorization header to be able to access protected Foundation APIs. +

+

+ + Authorization : Bearer <access token> + +

+

+ Upon recieving an access token, the Foundation will validate the token to ensure: +

+ +

+ Developer Sandbox +

+

+ You can use the Foundation API in Sandbox mode which provides a set of demonstration data that can be interacted with without affecting any client environment. +

+

+ Upon registering with our developer portal, you can immediately get familiar with the functionality our APIs offer and enjoy a hurdle free route to start developing your application +

+

+ Sandbox mode supports processing of all read and write requests so that you can build and test in confidence before submitting your application to our Marketplace. +

+

+ To access the sandbox, you'll need to register for a developer account at our Portal. You're then able to simply use those credentials provide them to our Authorization services in the normal way. The access token generated for your developer credentials will point our APIs at your sandbox data. +

+

+ Alternatively, our Interactive API Explorer will automatically grant access to sandbox data when you're logged into the Developer Portal. +

+

+ Errors +

+

+ Unsuccessful requests return an error response in JSON format. This includes a status code, a time stamp and textual description of the error: +

+

+

+          
+            Content-Type: application/json
+            
+{
+  "statusCode": 404,
+  "dateTime": "2019-04-23T18:25:43.511Z",
+  "description": "Contact RPT19000001 was not found."
+}
+              
+          
+        
+

+

+ Validation errors will also include a breakdown of the problems with the submitted payload: +

+

+

+          
+            Content-Type: application/json
+            
+{
+  "statusCode": 422,
+  "dateTime": "2019-04-23T18:25:43.511Z",
+  "description": "The submitted payload has failed validation.
+                  See the errors list for more information.",
+  "errors": [
+    {
+      "field" : "caption",
+      "message" : "Must be less than 50 characters in length."
+    }
+  ]
+}
+              
+          
+        
+

+

+ Rate limits +

+

+ You can make 1000 requests per minute to our APIs. Each response will include HTTP headers to provide information on the current rate limit statistics. +

+
+

+
+ If the rate limit is hit, a response similar to below will be issued: +

+

+

+          
+            HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1402010983 Retry-After: 30
+            
+ Content-Type: application/json + +{ + "statusCode": 429, + "dateTime": "2019-04-23T18:25:43.511Z", + "description": "Rate limit for API requests has been hit. + Your limit is 1000 requests per minute. + This limit will be reset in 30 seconds." +} + +
+
+

+

+ Pagination +

+

+ All collection API resources can be paged and share a common structure in their responses. Page size and offset is controlled by use of standardised query strings. +

+
+ Request +
+

+ Unless documented, the default page size is 25 and the maximum is 50. +

+

+ + + http://foundations.reapit.com/contacts?pageSize=10&pageNumber=2 + + +

+
+ Response +
+

+

+          
+            Content-Type: application/json
+            
+{
+  "pageNumber": 2,
+  "pageSize": 10,
+  "pageCount": 10,
+  "totalCount" : 142,
+  "data" : [
+    ...
+  ]
+}
+              
+          
+        
+

+

+ Resource expansion +

+

+ Some of the top level resources made available by the platform include resource expansion functionality. When fetching data from a resource expansion enabled endpoint, clients can optionally request that a response includes data from one or more related resources. +

+

+ This ability is to designed to reduce the number of required client-server roundtrips to obtain the data that a client needs for a specific use-case. +

+

+ Query parameters are used to govern this functionality, please see the specific documention of each end point for details. +

+
+ Request +
+

+ The example request below will fetch a list of contacts with resource expansion enabled for the identity checks nested collection: +

+

+ + http://foundations.reapit.com/contacts?embed=identityChecks + +

+
+ Response +
+

+ A paged response from the + + /contacts + + request example above: +

+

+

+          
+            Content-Type: application/json
+            
+{
+  "data" :
+  [
+    {
+      "id" : "RPT1900001",
+      "title" : "Mr",
+      "forename" : "David",
+      "surname" : "Smith",
+      ...
+      "embedded": {
+          "identityChecks" :
+          [
+            {
+              "id" : "RPT1900050",
+              "contactId" : "RPT1900001",
+              "status" : "pending",
+              ...
+              }
+            ]
+        }
+      }
+  ],
+  "pageNumber": 1,
+  "pageSize": 25,
+  "pageCount": 25,
+  "totalCount" : 142,
+}
+              
+          
+        
+

+

+ Metadata +

+

+ Resources that support editing have a + + metadata + + attribute available in their payload. This attribute can be used to set a JSON data fragment against a specific resource by including the metadata attribute in POST and PATCH requests. This will subsequently be included in future fetches of that resource. +

+

+ Metadata should be used to store additional, structured information against an object. This allows our clients to build upon the resource returned by the API and create a point of integration between our platform and third party applications. A common use case would be to store a unique identifier from an external system. +

+

+ Once metadata has been submitted to a representation, a JSON schema is built and used to validate future metadata submissions to the same endpoint to keep ensure that data is valid and consistant. +

+

+ Information stored in metadata is specific to your application and is not available to other Reapit or third party applications. Do not store any sensitive information (personally identifiable information, bank details, etc.) as metadata. +

+ + + +`; + +exports[`ApiDocs should match snapshot after changing hash 1`] = ` + + + +

Foundations API

@@ -28,17 +683,17 @@ exports[`ApiDocs should match a snapshot 1`] = ` with all resources accessible using standard - HTTP methods - + and returning predictable - response codes - + . All request and response bodies, including errors, are encoded in to be submitted as part of requests sent to protected endpoints. For more information how our APIs are secured, please see - Authorization - + .

Alternatively, our - Developer Sandbox - + provides a quick start experience to quickly get to grips with the platform and start developing.

@@ -228,14 +883,7 @@ exports[`ApiDocs should match a snapshot 1`] = ` Registering your application

- Your application must be registered with our Marketplace before it can interact with data, functionality and assets provided by the Foundations API. For more information on how to register your application, see our - - - Marketplace - - documentation. + Your application must be registered with our Marketplace before it can interact with data, functionality and assets provided by the Foundations API. For more information on how to register your application, see our Marketplace documentation.

As part of creating your application, you'll be required to choose the @@ -260,13 +908,7 @@ exports[`ApiDocs should match a snapshot 1`] = ` As part of the installation process, clients are required to agree to the scopes that your application requires before your application becomes accessible to end users. Applications cannot interact with client data or assets without prior approval from the client.

- Once installed, an application can access Foundation services on an end users behalf. The recommended way to achieve this is to use one of our - - Client Libraries - - , however you can interact directly with our APIs as detailed below. + Once installed, an application can access Foundation services on an end users behalf. The recommended way to achieve this is to use one of our Client Libraries, however you can interact directly with our APIs as detailed below.

Create an authorization code @@ -564,7 +1206,7 @@ exports[`ApiDocs should match a snapshot 1`] = ` "data" : [ ... ] -} +} @@ -619,7 +1261,7 @@ exports[`ApiDocs should match a snapshot 1`] = ` "surname" : "Smith", ... "embedded": { - "identityChecks" : + "identityChecks" : [ { "id" : "RPT1900050", diff --git a/src/components/pages/__tests__/api-docs.tsx b/src/components/pages/__tests__/api-docs.tsx index e788238dbd..fb5d4a5833 100644 --- a/src/components/pages/__tests__/api-docs.tsx +++ b/src/components/pages/__tests__/api-docs.tsx @@ -1,12 +1,54 @@ import * as React from 'react' -import { shallow } from 'enzyme' +import { shallow, mount } from 'enzyme' import toJson from 'enzyme-to-json' -import ApiDocs from '../api-docs' +import ApiDocs, { handleUseLayoutEffect } from '../api-docs' jest.mock('../../../core/store') +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: jest.fn(() => ({ + location: { hash: '' } + })) +})) + +let scrollIntoViewMock +beforeEach(() => { + document.body.innerHTML = '

' + scrollIntoViewMock = jest.fn() + HTMLElement.prototype.scrollIntoView = scrollIntoViewMock +}) describe('ApiDocs', () => { it('should match a snapshot', () => { - expect(toJson(shallow())).toMatchSnapshot() + expect(shallow()).toMatchSnapshot() + jest.resetModules() + }) + + it('should match snapshot after changing hash', () => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: jest.fn(() => ({ + location: { hash: '#authorization' } + })) + })) + expect(shallow()).toMatchSnapshot() + }) + + it('should call scrollIntoView when have matching id', () => { + const fn = handleUseLayoutEffect('#authorization') + fn() + expect(scrollIntoViewMock).toBeCalled() + }) + + it('should not call scrollIntoView when no matching id', () => { + const fn = handleUseLayoutEffect('#authorization123') + fn() + expect(scrollIntoViewMock).toHaveBeenCalledTimes(0) + }) + + it('should call scrollIntoView to id="api" when there no hash', () => { + const fn = handleUseLayoutEffect('') + fn() + expect(scrollIntoViewMock).toBeCalled() }) }) diff --git a/src/components/pages/api-docs.tsx b/src/components/pages/api-docs.tsx index 32e0fda4df..9a235f84ac 100644 --- a/src/components/pages/api-docs.tsx +++ b/src/components/pages/api-docs.tsx @@ -1,22 +1,36 @@ import * as React from 'react' +import { Link, useLocation } from 'react-router-dom' import apiDocStyles from '@/styles/pages/api-docs.scss?mod' import { FlexContainerResponsive, Content, H3, H4, H5, Table, FlexContainerBasic } from '@reapit/elements' -const ApiDocsPage: React.SFC = () => { +export const handleUseLayoutEffect = hash => () => { + if (document) { + const element = hash ? document.getElementById(hash.slice(1)) : document.getElementById('api') + if (element) { + element.scrollIntoView() + } + } +} + +const ApiDocsPage: React.FC = () => { + const { hash } = useLocation() + /* scroll before paint by using useLayoutEffect */ + React.useLayoutEffect(handleUseLayoutEffect(hash), [hash]) + return ( -

Foundations API

+

Foundations API

Overview

The Foundations API is organised around{' '} REST {' '} - with all resources accessible using standard HTTP methods and returning - predictable response codes. All request and response bodies, including errors, - are encoded in JSON and served over{' '} + with all resources accessible using standard HTTP methods and returning + predictable response codes. All request and response bodies, including + errors, are encoded in JSON and served over{' '} HTTPS TLS v1.1+ to ensure data privacy and security.

@@ -24,11 +38,11 @@ const ApiDocsPage: React.SFC = () => { Our API resources are secured and require an{' '} authorization JWT bearer token to be submitted as part of requests sent to protected endpoints. For more information how our APIs are secured, please see{' '} - Authorization. + Authorization.

- Alternatively, our Developer Sandbox provides a quick start experience to - quickly get to grips with the platform and start developing. + Alternatively, our Developer Sandbox provides a quick start experience + to quickly get to grips with the platform and start developing.

REST

HTTP Methods
@@ -160,8 +174,8 @@ const ApiDocsPage: React.SFC = () => {
Registering your application

Your application must be registered with our Marketplace before it can interact with data, functionality and - assets provided by the Foundations API. For more information on how to register your application, see our{' '} - Marketplace documentation. + assets provided by the Foundations API. For more information on how to register your application, see our + Marketplace documentation.

As part of creating your application, you'll be required to choose the{' '} @@ -186,8 +200,8 @@ const ApiDocsPage: React.SFC = () => {

Once installed, an application can access Foundation services on an end users behalf. The recommended way to - achieve this is to use one of our Client Libraries, however you can interact - directly with our APIs as detailed below. + achieve this is to use one of our Client Libraries, however you can interact directly with our APIs as + detailed below.

Create an authorization code

@@ -438,7 +452,7 @@ const ApiDocsPage: React.SFC = () => { "data" : [ ... ] -} +} `} @@ -484,7 +498,7 @@ const ApiDocsPage: React.SFC = () => { "surname" : "Smith", ... "embedded": { - "identityChecks" : + "identityChecks" : [ { "id" : "RPT1900050",