DIS 3.0 Usage Guide

1.Authentication Guidance

1.1 Introduction

DIS 3.0 provides all services via RESTful API endpoints.All APIs follow OpenAPI 3.0 standard where full specifications and schemas can be found in our APIS.

1.2 Services

  • MemberClub
    MemberClub is the main service that handles club and individual related logic.

  • Search Service
    SearchService provides search APIs to resources, like individuals and clubs.

  • IAM
    IAM (Identity and Access Management) is used for maintaining and checking permissions between resources.

  • RI Email
    RI Email (Rotary International) is used for verify email uniqueness in the whole RI system.

1.3 Terminologies

  • Ocp-Apim-Subscription-Key
    Ocp-Apim-Subscription-Key is the identity of your application. DIS will determine your access level based on this key, It must be provided in header during every API call.

  • Identity
    Identity header is usually required as an ID field for specifying who is executing this request. DIS will determine if the action can proceed based on the access level of this requestor to the resource that is being read/written."

  • ImpersonatorId
    ImpersonatorId is the staffId who wants to access a user's account.

  • HATEOAS
    HATEOAS is an RESTful architectural style which provides hypermedia links in the response contents so that the client can dynamically navigate to the appropriate resource by traversing the hypermedia links. Please refer to REST API Tutorial.

  • JSON Patch
    JSON Patch is a format for describing changes to a JSON document. It can be used to avoid sending a whole document when only a part has changed. When used in combination with the HTTP PATCH method, it allows partial updates for HTTP APIs in a standards compliant way.Please refer to jsonpatch.com.

  • Internal Client Access
    Consumer with Internal subscription key.

  • External Client Access
    Consumer with External subscription key.

  • DIS Client Access
    Consumer with DIS subscription key. According to the minimum permission principle, there's no permission of DIS key by default. Apply higher permission for DIS key when a feature need it.

1.4 Impersonation

Impersonation allows a staff acts as a user and operate the user's data. ImpersonatorId needs to be provided in the header and API will validate the authorization, the staff can only impersonate the user after being authorized.

The authorization process is to validate Okta session, if the session is valid, the authorization will be successful.

If the session is invalid or session expired, the authorization will fail and API will return 401 error.

1.5 Getting Started

  • DIS 3.0 would have 3 type of services.

    Internal Service and External Service are the consumers of DIS 3.0. We distinguish them based on whether the application needs the end-user credential. In general, an Internal Service is a highly-trust application and no end-user authorization is needed. An example is a cron job that uses an API to export information for reporting. An External Service is an application which needs the end-user credentials. Sometimes an application would be Internal Service and External Service at the same time, e.g. MyRotary is an application includes a backend and frontend(s), it is a highly-trust application, which has a cron job to fetch all individuals information for reporting, now it's acting like an Internal Service. It also has some feature consume DIS 3.0 on behalf of end-user, now it's acting as an External Service. Internal Service could access any data that a consumer could access. External Service could access data based on end-user permission.

    DIS Service(MemberClub, IAM, SearchService, RIEmail), which is the implementation of DIS 3.0 itself, could potentially access any needed data in DIS 3.0 scope. However, based on the principle of least privilege, it's better to add it to the white list of specific API when needed. For example, there are some APIs in IAM, like ResourceOwner and Affiliation, could not be accessed by Internal Service and External Service but DIS Service.

  • Please contact your point of contact to acquire your Ocp-Apim-Subscription-Key key before continuing to the next steps.

Examples

Sample POST request (Create an individual)
curl -X POST \ 
https://ri-u-usc-dis-am.azure-api.net/memberclub/individuals \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: [YOUR_KEY_HERE]' \
-d '{
"firstName": "Lucy",
"lastName": "Jones",
"gender": "Female",
"primaryLanguage": {
"languageId": "abk"
}
}'

Response with HATEOAS links:

If the requestor has no permission to the target resource from IAM, DIS3 will return a link with empty method.

HTTP/1.1 201 Created 
Content-Type: application/hal+json; charset=utf-8
{
"id": "[INDIVIDUAL_ID]",
"firstName": "Lucy",
"lastName": "Jones",
"gender": "Female",
"primaryLanguage": {
"language": "Abkhazian",
"languageId": "abk"
},
"_links": {
"self": {
"href": "/individuals/[INDIVIDUAL_ID]",
"method": "GET|PATCH"
},
"photo": {
"href": "/individuals/[INDIVIDUAL_ID]/photo",
"method": "PUT|DELETE"
},
"onlineid": {
"href": "/individuals/[INDIVIDUAL_ID]/onlineid",
"method": ""
},
"programs": {
"href": "/individuals/[INDIVIDUAL_ID]/programs",
"method": "GET|POST"
}
}
}
Sample PATCH request (Update an individual)
curl -X PATCH \ 
https://ri-u-usc-dis-am.azure-api.net/memberclub/individuals/[TARGET_INDIVIDUAL_ID_HERE] \
-H 'Content-Type: application/json' \
-H 'Identity: [REQUESTOR_INDIVIDUAL_ID_HERE]' \
-H 'ImpersonatorId: [STAFF_ID_FOR_IMPERSONATON]' \
-H 'Ocp-Apim-Subscription-Key: [YOUR_KEY_HERE]' \
-d '[
{
"op": "replace",
"path": "/primaryAddress",
"value": {
"type": "Home",
"lineOne": "primary-update",
"lineTwo": "LineTwo",
"lineThree": "LineThree",
"countryId": "USA",
"city": "NewYork",
"stateId": "AA",
"internationalProvince": "",
"postalCode": "100001"
}
}
]'
Response:
HTTP/1.1 200 OK 

2. Metadata in DIS

  • GET /metadata/countries

  • GET /metadata/states

  • GET /metadata/languages

  • GET /metadata/expertise-areas

  • GET /metadata/expertise-levels

  • GET /metadata/leadership-roles

  • GET /metadata/programs

  • GET /metadata/sharing-permission

  • GET /metadata/termination-reasons

  • GET /metadata/area-of-focus

3. Error design and common error

3.1 Error design

Validation error message structure:
{ 
"status": 400,
"type": "https://api.rotary.org/validation-error",
"title": "ValidationError",
"detail": "See errors for detailed information",
"errors": [
{
"code": "RequiredField",
"description": "individualId is required",
"source": "individualId",
"arguments": {}
}
]
}
Other error message structure:
{ 
"status": 404,
"type": "https://api.rotary.org/not-found",
"title": "NotFound",
"detail": "club is not found",
"source": "clubId"
}

Details for error code defination refer to DIS 3.0 Error Codes

3.2 Common error

  • 400 Validation error or illegal operation

  • 401 Authentication error

  • 403 Forbidden

  • 404 Resource not found

  • 406 Header 'Accept' error

  • 409 Conflict Exception

  • 500 Bad data Exception or internalServer error, or Timeout in API Management

  • 503 Temporary service error

  • 504 Gateway Timeout, or request processing Timeout

The response sample will include all possible HTTP error code that listed here except 401 Unauthorized and 403 Forbidden. These two errors are common for all HAL APIs.

Example for 401 Unauthorized

{
"status": 401,
"type": "https://api.rotary.org/unauthorized",
"title": "Unauthorized",
"detail": "Impersonation session not found",
"source": "requestor, impersonatorId"
}

Example for 403 Forbidden

{
"status": 403,
"type": "https://api.rotary.org/forbidden",
"title": "Forbidden",
"detail": "No permission"
}

Example for 500 Timeout, which is return by API Management. The default Timeout of API Management is 240s.

Headers:
errorSource: forward-request
errorReason: Timeout
errorMessage: Request to the backend service timed out
errorSection: backend
Body:
{
"statusCode": 500,
"message": "Request to the backend service timed out"
}

Example for 504 Timeout, which is return by IAM Service. This error is raised when IAM waiting CosmosDB response over 60s.

Headers:
errorSource: forward-request
errorReason: Timeout
errorMessage: Request to the backend service timed out
errorSection: backend
Body:
{
"Status": 504,
"Type": "https://api.rotary.org/gateway-timeout",
"Title": "LockTimeout",
"Detail": "Timeout when processing request, please retry later"
}

4.Access Level

Manager

One is who has the highest access level (View and edit) to the resource (individual, club, membership, leadership included)

For example:

  • Lucy is the manager to herself; she can view and edit her information.

  • If Lucy is an officer of one rotary club, she has the manager access level to the club profile and membership/leadership of this club. So, she can view and edit them.

Contributor

One is who has the highest access level (View and edit) to the resource (individual profile) but has limitation to some resource.

For example:

  • If Lucy is an officer of one rotary club, she has the contributor access level to others’ profile. It means she can view and edit Lily’s information except photo (Lucy can view Lily’s photo only)

Viewer

One only can view the resource (individual, club, membership, leadership included).

For example:

  • If Lily is a Rotarian (not an officer), she only can view the club’ s information.

Limited Viewer

One only can view the resource’s partly information.

For example:

  • If Lily's membership was terminated, she can view the club’ s information except some important information like phone number, mailing address etc.

No permission

One cannot view the resource

For example:

  • If Lily's membership was terminated, she cannot view any membership.

5. FAQs

5.1 Why are Request Parameters with 'optional' label required?

Some APIs have request parameters marked (optional) after the parameter name, but has a description like 'Required, NetForum riIndividualId, riIndividualId > 0', for example the api named 'GetIndividualByRiIndividualId'.

We use Azure API Management to apply authentication, authorization, and usage limits. As we mentioned before the API 'GetIndividualByRiIndividualId', the request URL should be 'https://ri-u-usc-dis-am.azure-api.net/memberclub/individuals[?riIndividualId]'. If we marked the riIndividualId without optional the API Management will check the request URL with parameter riIndividualId provided, and if you request the URL without the parameter the API Management will automatic response like:

{
"statusCode": 404,
"message": "Resource not found"
}

The request doesn't reach the backend service.

So we mark the parameter with optional and add the description to explain whether the parameter is required. If you request the URL without the required parameter, it will not be intercepted by the API Management and will be handled by the backend service. Then you will get the error message will more details like:

{
"status": 400,
"type": "https://api.rotary.org/validation-error",
"title": "ValidationError",
"detail": "See errors for detailed information",
"errors": [
{
"code": "Field_Required",
"description": "riIndividualId is required",
"source": "riIndividualId",
"arguments": {}
}
]
}

We want to make the error more detail. And it will tell you that the request lack parameters other than the URL not existed.

5.2 How to know which fields in the request body are required ?

You can check the request body presenting as example and schema, you can switch between them in the detail of the API. The fields that are required in the request body will be marked in the schema. 

For example:
{
"description": "",
"required": [
"individualId",
"type",
"admissionDate"
],
"type": "object",
"properties": {
"individualId": {
"type": "string"
},
"sponsorIds": {
"description": "Can only add sponsor to member in rotary club\nCan't add more than two sponsors\nSponsor can't be duplicated in the request\nSponsorId must be active member not honorary member",
"uniqueItems": false,
"type": "array",
"items": {
"format": "uuid",
"type": "string"
}
},
"type": {
"description": "type must be one of Member, Honorary",
"type": "string"
},
"admissionDate": {
"description": "admissionDate must be a valid date with format yyyy-MM-dd\nadmissionDate cannot be more than 1 day in the future (current date + 1)\nadmissionDate must be within 30 days",
"type": "string"
}
},
"example": {
"individualId": "a5087007-ec67-4085-844e-7c9587ecca9e",
"sponsorIds": [],
"type": "Member",
"admissionDate": "2019-12-03"
}
}

Our APIs

Picture

MemberClub

MemberClub is the main service that handles club and individual related logic.

Read

Picture

IAM

IAM (Identity and Access Management) is used for maintaining and checking permissions between resources.

Read

Picture

Search Service

SearchService provides search APIs to resources, like individuals and clubs.

Read

Picture

RI Email

RI Email (Rotary International) is used for verify email uniqueness in the whole RI system.

Read