几个增加 RESTful API 设计的可用性的技巧

Some Techniques for Better Usability in REST API Design

Someone said that API designers are UX engineers for developers. Good API design should be easy to use for consumers as well as easy to be implemented by developers.

Here are some techniques I summarized from my API design tasks. Let me know if it is helpful or you have more ideas on how to design a easy-to-use API.

Return 200 OK with Empty Array or 404 Not Found?

Problem

Sometimes, it is hard to tell if a GET API should return 200 OK with an empty array or it should return 404 not found. Actually, the answer is how the API client would like to handle it.

A 4XX response usually indicate there is something wrong in client’s request. Client also will treat it with a customized error page. Before an API designer makes a decision, it’s better to ask client developers how they will use the response.

Technique

However, there are common practice on which status code we should use. A API should return 200 OK with empty array if the purpose is to search records for a player or other criteria since an empty array isn’t an error caused by the client. It just means there isn’t any records of the player. However, the API should return 404 if the player cannot be found in the system because the client may entered a wrong player ID and the system should prompt this error to the user.

Example

Here is an example. In this example, the system tries to search active user sessions of a station. It returns 200 OK with an empty array while it returns 404 not found if station ID cannot be found.
在这里插入图片描述

Use controller or Use PUT to modify a resource?

Problem

In RESTful APIs, PUT is suggested to modify a resource but we also see APIs use controller with a POST for resource modification. Which way is better?

When you use put, you use body to wrap the object to be modified but the issue is we only need to change a status of an object, which is minimal change. You may confuse a developer in such case if you transfer an entire object to service for this purpose.

Technique

Use controller to minimize the number of parameters if you only want to change a status.

Example

You can see the difference between changing status of CPV (chip purchase voucher) with PUT and Controller.

PUT

The following images show the API use put to change a CPV status to redeemed and voided. The request body is CPVInfo object but you can see the only mattered properties are CPV ID, CPV status, and transaction info among all the properties. The API designer needs to tell developers which properties should be used in the API. This lowers usability of the API. The good news is that this make it easier to see transaction details if we need to analyze logs because the request body includes all the detail information of the CPV. We don’t need to reference other information source such as database.
在这里插入图片描述
在这里插入图片描述
Controller

The following example uses redeem and void controllers to redeem and void a CPV. You can see only transaction information is needed in request body. This makes much clear to API developers what parameters are actually should be used in the implementation. There isn’t CPV related parameters except CPV ID.

请添加图片描述

Use Read Only to specify properties that only should be shown in a response

Problem

Designers always want to reuse schemas to save their effort. For the above example, a CPVInfo object definition is used in both issue CPV API and redeem/void CPV API but not all properties of CPVInfo object are used in said APIs. Some properties should only be used in request and some properties are supposed to be used in response. How can API designers describe the usage scenario in this case?

Technique

In open API specification, you can mark a property as ReadOnly, which means this property shouldn’t be used in request and it will only be shown in response.

Example

In the following example, I mark CPVInfo.IssuanceTime as ReadOnly since it is generated when a CPV was issued at service side. It’s not required when client tries to issue a CPV. As you can see, it won’t appear in issue CPV API request.

在这里插入图片描述
在这里插入图片描述
IssuanceTime is marked as ReadOnly in CPVInfo schema.
在这里插入图片描述

Use Problem Details to show errors to client

Problem

For API errors, we often see different products use different error object definition. Actually, there is an industry standard for RESTful API error object definition. It is also recommended in REST API guideline and adopted by .Net Core.

Technique

Use ProblemDetails to describe API errors. It is defined in https://tools.ietf.org/html/rfc7807. It’s easier for your API consumer to understand and use your error description using industry standard. They can easily find documents of it online.

Example
在这里插入图片描述

Use sub path for sub transaction types

Problem

We need to use many words to document an API usage if this API has a few special cases or sub types. In most cases, our user cannot use the API correctly without reading the document. For PA engineers, it also takes time to test all the special cases or sub types if they are packaged in one API. Any modification to the API causes a full regression.

Technique

We can use sub path for special cases or sub types under the API so that user can learn all these cases and sub types by just reading the API path and testers can test the API cases one by one without worrying a chained error effect when there is a modification.

Example

Zero Play Rating

The following request is used to add a table rating to CMS. Users need to fill quite a few parameters to post a rating. This works in most cases but there is a special case which is that a player doesn’t play. We call it Zero Play. To post a Zero Play rating, users need to figure out Zero Play parameters pattern, which will take some time.

The solution to it is to add a sub path to the existing Post Rating API. For this example, we will change /api/v1/table-ratings to /api/v1/table-ratings/zero-play and remove the unnecessary parameters from the request. In this way, users can know how to post a Zero Play rating just from the API path.

{
  "transactionInfo": {
    "transactionTime": "2020-07-08T01:18:07.0623569+00:00",
    "postedBy": "*****",
    "verifiedBy": "*****",
    "enteredBy": "******",
    "workstation": "123"
  },
  "ratingId": 38020,
  "sourceId": "1",
  "sourceName": "test table",
  "playerId": 125,
  "programId": 0,
  "tableID": "LA01BJ01",
  "gameType": "BJ",
  "gameName": "BlackJackBJ",
  "gamingDate": "2020-07-08T01:18:07.0623888+00:00",
  "shift": "1",
  "pitID": 1,
  "pitName": "Poker 1",
  "position": 2,
  "row": 1,
  "startTime": "2020-07-08T01:16:07.0624008+00:00",
  "endTime": "2020-07-08T01:18:07.06241+00:00",
  "timePlayed": 500,
  "averageBet": 544,
  "speed": 49,
  "handsPlayed": 6,
  "cashIn": 3951,
  "chipsIn": 1078,
  "markersIn": 1287,
  "moneyPlays": 1424,
  "chipsOut": 2908,
  "ratingIns": [
    {
      "code": "1",
      "description": "bla in",
      "amount": 2528,
      "cashEquivalent": false,
      "displayOrdinal": 0
    },
    {
      "code": "CashIn",
      "description": "Cash In",
      "amount": 15255,
      "cashEquivalent": false,
      "displayOrdinal": 0
    },
    {
      "code": "CashlessIn",
      "description": "Cashless In",
      "amount": 2589,
      "cashEquivalent": false,
      "displayOrdinal": 0
    }
  ],
  "ratingOuts": [
    {
      "code": "2",
      "description": "bla out",
      "amount": 1766,
      "cashEquivalent": false,
      "displayOrdinal": 0
    },
    {
      "code": "ChipsOut",
      "description": "Chips Out",
      "amount": 6582,
      "cashEquivalent": false,
      "displayOrdinal": 0
    },
    {
      "code": "CPVRedeem",
      "description": "CPV Redeem",
      "amount": 5430,
      "cashEquivalent": false,
      "displayOrdinal": 0
    }
  ],
  "netBuyIn": 390,
  "winLoss": 743,
  "skill": "Average",
  "ratingComments": "test comment",
  "skillFactor": 4,
  "dealer": "******",
  "marker": [
    {
      "documentId": 198273,
      "amount": 10
    }
  ]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

surfirst

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值