Search code examples
restapirestful-architecturehateoas

REST: How to return back the next action url in response body?


We have created an API to get user details. To get any particular user details, one needs to enter a verified number.

The API looks like:

GET /api/details/?number=983984348&userid=123

Here userid is the id of the user who's detail we need and the number is mobile-number of person who wants to get those details. If the number is verified, we get back details of user 123. If the number is not verified, we send back status as Not Verified.

If the client gets not verified status back, the client needs to hit verification API. The API looks like:

/api/verify/?number=983984348

Once this API is hit, client gets URL that needs to be hit to verify.

Currently, we have hard-coded this API url /api/verify/?number=983984348 at each client BUT as per HATEOAS it's incorrect as it recommends it should be guided by server.

I have no clue how should this API url be sent from client to server i.e using simple response body OR in response headers? Can someone explain me how such navigation should be guided from the server to the client?


Solution

  • Just thinking about the scope of your question, if you hit the /api/details/?number=983984348&userid=123 uri, which tells a client that the number wasn't verified, then you can also include in the body of the the response a URI to use.

    Example (using HAL, encoded as JS not JSON, but applicable to other hypermedia formats just the same):

    {
      _links : {
        self : { href: '/api/details/?number=983984348&userid=123' },
        verify : { href: '/api/verify/?number=983984348' }
      }
      verified: false
    }
    

    A HTTP Link header can also work:

    Link: </api/verify/?number=983984348>; rel="verify"
    

    In our case we built an open-source javascript REST client that supports either header or the hal _link, and doesn't care which one it is. Our client would do something like this:

    var client;
    // usually you'll want to discover this url as well.
    var user = await client.getResource('/api/verify/?number=983984348');
    var userBody = await client.get();
    
    if (!userBody.verified) {
      var verifyResource = await userBody.follow('verify');
      // verifyResource.put() might come next?
    }
    

    Not sure if that last bit helps, but it helped me think about this.