Rest – Support multiple request formats for single REST endpoint

api-designrest

I'm building an REST API that exposes a callback method for a 3rd-party service.

Let's imagine that there are two similar (but not identical) 3rd-party services. They both call back my API (POST /api/callback), but have different request formats (JSON):

Provider 1

{"sender": "Provider1", "field1": "value1", "fieldN": "valueN"}

Provider 2

{"sender": "Provider2", "key1": "value1", "keyN": "valueN"}

So they have only one common parameter (sender) and others might differ.

Next, I have two corresponding DTOs that JSON should be mapped to

Pseudo-code:

class Provider1DTO {
    string sender;
    string field1;
    string fieldN;
}

class Provider2DTO {
    string sender;
    string key1;
    string keyN;
}

Provider1DTO dto1 = mapper.readJSON(json, Provider1DTO.class)
Provider2DTO dto2 = mapper.readJSON(json, Provider2DTO.class)

Question:

What is correct approach to achieve per-provider customization?

1) Introduce separate endpoints

/api/callback/provider1
/api/callback/provider2

2) Use single endpoint and analyze sender field of request body to map JSON to the relevant DTO

3) Use single endpoint and analyze X-Sender-ID (example) of request headers to map JSON to the relevant DTO

Approach #2 seems best to me, since I can't force providers to use custom request headers (as per #3).
As for #1: there might be multiple services that provide identical request format, so there's no need to have separate endpoint

What are your thoughts on this? Thanks in advance

Best Answer

Your server's job is to represent a resource, identified by a URI. That resource can have multiple representations (formats/serialisations). You have one resource, two request formats (both JSON schemas) you can accept, and two response formats you can return (also both JSON schemas).

Whilst I suggest that all clients which are able to adapt would themselves be better off adapting to the more widespread JSON schema used (thus able to talk to other servers in future that already use this format), if that cannot be done, I recommend negotiating with the HTTP Accept header. Have your clients send the schema they are requesting with in a Content-Type header, and the schema they want back in an Accept header. You may need to create some new media types for this. You can create private ones or you can register them with IANA if you think they should become public.

Both clients should send requests to a single URL that is not called e.g. "/api/do-something", but more like "/type-of-thing/thing" — URIs should be nouns that say what the thing is you get when you do a GET request. Putting "api" in the URL is a fallacy: all websites are APIs, regardless of whether client software is machine- or human-driven, and regardless of whether they are serving PDF files or XHTML or cat images or JSON.