bcc-code / developer.bcc.no

BCC Developer Portal with technical documentation and other resources for developers
https://developer.bcc.no/
5 stars 5 forks source link

[ADR] API contract conventions #46

Open StevenMalaihollo opened 2 years ago

StevenMalaihollo commented 2 years ago

Context

For the Core APIs we are setting a standard for how OpenAPIs should look like within BCC.

Proposition

Enums

The values used within Enums will be PascalCase. This is to stay backwards compatible with previously connected systems.

Timestamps

Dates where time is irrelevant (such as birth dates, deceased dates, contract dates etc.) should look like: 2022-05-03. These dates should not have a timezone or time component. Regular timestamps should conform to the iso 8601. This means that a timezone and time component is stored.

Null values

Should be looked at on a case by case basis.

Querying

For querying in our APIs we want to build according to the Odata query syntax. This syntax should only be implemented according to need. For now we are interesting in using:

github-actions[bot] commented 2 years ago

Remember that ADRs are publicly available hence do not include any confidential information in the issue description! To read more about ADR please refer to documentation.

StevenMalaihollo commented 2 years ago

Querying revisit

Odata query implementation does not fit well with our APIs. Other standards don't seem to help us or the consumer either. So we will build a strong set of custom querying features based on DirectUs fields:

Responses

Some standards make use of wrapper types like meta, data and more. In general we follow the way DirectUs structures responses.

type Wrapped = {
    data?: object | object[]; // Can be omitted if there is an error
    meta?: Meta; // Can be omitted for single item requests
    error?: ErrorResponse; // Can be omitted if there is no error or 'errors' is defined
    errors?: ErrorResponse[]; // Can be omitted if there is no error or 'error' is defined
};

interface Meta {
    total: number;
    skipped: number;
    limit: number;
    // Other optional properties
}

interface ErrorResponse {
    message: string;
    code?: string;
    // Other optional properties
}

// examples:
const errorResponse: Wrapped = {
    error: {
        code: 'invalid-query',
        message: "Invalid query: 'foo' is not a valid query parameter",
    },
};

const singleItemResponse: Wrapped = {
    data: {
        id: '123',
        name: 'John Doe',
    },
};

const multipleItemsResponse: Wrapped = {
    data: [
        {
            id: '123',
            name: 'John Doe',
        },
        {
            id: '456',
            name: 'Jane Doe',
        },
    ],
    meta: {
        total: 7,
        skipped: 0,
        limit: 2,
    },
};
rvanoord commented 2 years ago

I like the proposal @JakubC-projects. We could consider using errorCode instead of just code which is a bit ambiguous (since HTTP status code is also relevant in this context).

The type Wrapped could perhaps be called ApiResponse or ResponseMessage or similar.