Напишите приятный интерфейс API (1)

Java
Напишите приятный интерфейс API (1)

введение

Интерфейс API — это мост между сервером и клиентом.减少Совместное время отладки между клиентом и сервером больше внимания уделяет оптимизации собственного кода и логике бизнес-уровня.

Очки знаний по дизайну API

Состав API

Хороший интерфейс API должен быть оптимизирован по следующим направлениям:

  1. Точный протокол API
  2. точный тип контента
  3. Унифицированный тип возврата и обработка исключений
  4. Хорошая система контроля версий интерфейса
  5. Путь интерфейса API максимально короткий и унифицированный
  6. Производительность и безопасность

упражняться

Разделение типов протоколов API

  • GET: получить определенный ресурс или список ресурсов с сервера.
  • POST: создать новый ресурс на сервере.
  • PUT: обновить ресурс на сервере в целом.
  • PATCH: обновить только один атрибут ресурса на сервере.
  • DELETE: удалить ресурс на сервере.
  • HEAD : получить метаданные ресурса, такие как хеш-значение данных или время последнего обновления.
  • ПАРАМЕТРЫ: Получить информацию о том, что клиент может работать с ресурсом.

вGET,POST,PUT,PATCH,DELETEЭти пять протоколов чаще всего используются при ежедневной разработке CRUD. Анализ бизнес-сценариев с пользовательскими модулями

//获取用户列表(分页)
@GetMapping(value = "user")
public R selectList(UserSearch userSearch) {
    //userSearch 是一个搜索实体,里面有页码以及筛选条件属性
    return ResultUtil.data();
}
//获取单个用户信息
@GetMapping(value = "user/{id}")
public R selectOne(@PathVariable("id") String id) {
    //获取用户信息,与分页接口相同采用GET协议,用path传值id,区别与分页的接口
    return ResultUtil.data();
}
//新增用户
@PostMapping
public R add(@RequestBody User user) {
    //新增用户为新资源写入,采用POST接口,入参为用户的实体
    return ResultUtil.data();
}
//修改用户
@PutMapping("{id}")
public R upp(@PathVariable("id") String id,@RequestBody User user) {
    //修改用户所有属性,采用PUT接口,入参为用户的实体,同时id通过path传值
    return ResultUtil.data();
}
//删除用户
@DeleteMapping("{id}")
public R del(@PathVariable("id") String id) {
    //删除用户,采用DELETE协议,id通过path传值
    return ResultUtil.data();    
}
//修改用户部分属性(这里举例修改用户姓名)
@PatchMapping("user/userName/{id}")
public R uppPart(@PathVariable("id") String id,@PartBody String userName) {
    //修改用户部分属性,采用PATCH协议,在基础路由user后面加入要修改的属性名,入参用自定义注解@PartBody,原理就是解析body里单个叫userName的值,也可用Map接收,用自定义注解只是为了后期好维护.
    return ResultUtil.data();    
}
    

注:切记不要直接使用@RequestMapping()注解,不准确的接口协议定义会导致url重复,客户端也可以通过任意协议调用API接口,很不规范

Спецификация типа контента

application/x-www-form-urlencoded тип

пример кода

  • Формат передачи по умолчанию вида application/x-www-form-urlencoded, за которым часто следует кодировка, а именно: application/x-www-form-urlencoded; charset=utf-8
  • В этом формате передачи данные передаются в виде пар ключ-значение.
  • Когда это запрос GET, браузер преобразует данные формы в строку (имя1=значение1&имя2=значение2...) с методом кодирования x-www-form-urlencoded, а затем добавляет строку в конец URL-адреса. и отделяет его ? , загрузите этот новый URL. Параметры должны быть закодированы и сериализованы в urlencode.
  • Когда это запрос POST, браузер инкапсулирует данные формы в тело http, и получающий объект не может быть украшен аннотацией @RequestBody.

тип multipart/form-data

пример кода

  • Расширенный формат передачи для формы multipart/form-data
  • В этом формате передачи вся форма будет разделена на элементы управления, и каждая часть будет дополнена Content-Disposition (данные формы или файл), Content-Type (по умолчанию text/plain), name (имя элемента управления) и другую информацию и добавьте разделитель (границу).
  • Когда это запрос GET, объект входного параметра или отдельный атрибут могут находиться во взаимно однозначном соответствии с входящей парой ключ-значение имени.
  • Когда это запрос POST, браузер инкапсулирует данные формы в тело http, и получающий объект не может быть украшен аннотацией @RequestBody.

тип приложения/json

пример кода

  • Передача application/json JSON, теперь рекомендуемый способ передачи
  • В этом транспортном формате тело данных представляет собой сериализованную строку JSON.
  • Когда это запрос GET, имя параметра может быть передано по значению, имя параметра является значением атрибута в объекте и украшено аннотацией @RequestBody, а входной параметр, соответствующий имени параметра, может быть получен напрямую.
  • Когда это запрос POST, входные параметры инкапсулируются в тело, а принимающий объект украшается аннотацией @RequestBody.

Единый класс возврата

Необходимо унифицировать возвращаемый класс.После унификации клиенту нужен только общедоступный класс синтаксического анализа.Соответствующая бизнес-модель помещается в общий объект результата, и клиенту нужно только использовать соответствующий синтаксический анализатор для синтаксического анализа остальных.

вернуть класс R

@Data
public class R<T> implements Serializable
    private static final long serialVersionUID = 1L;
    //标识请求是否成功
    private boolean success;
    //操作成功或者失败后,客户端的提示信息
    private String message;
    //http状态码或者自定义的异常状态码
    private Integer code;
    //当前请求的返回时间
    private long timestamp = System.currentTimeMillis();
    //返回给客户端的业务主体数据,可为列表或者单个对象
    private T result;
}

Инкапсулирует возвращаемый класс инструмента класса ResultUtil.

В основном он инкапсулирует некоторые часто используемые статические методы успеха, отказа или возвращаемых параметров.Когда уровень управления возвращается к внешнему интерфейсу, ему нужно только вернуть метод, соответствующий ResultUtil.xxx()Пример кода ResultUtil

Код ошибки и сообщение ErrorCode

Определите ErrorCode с типом перечисления.Когда программа работает ненормально, вы можете напрямую вызвать ошибку (целочисленный код, строковое сообщение), чтобы вернуть клиенту соответствующее бизнес-исключение или другое системное исключение.Пример кода ErrorCode

Унифицированная обработка исключений

Класс перехвата исключений GlobalExceptionHandler

Определите класс GlobalExceptionHandler, используйте@ControllerAdviceМодификация может обеспечить унифицированный перехват исключений, и в примере кода перехватываются некоторые распространенные типы исключений.

//参照格式
//ExceptionHandler 指定需要拦截的异常类型
@ExceptionHandler(value = Exception.class)
@ResponseBody
//HttpServletRequest 可得到对应的请求参数,Exception 对象可得到对应的异常输出,可记录在日志中便于排查,再返回给客户端相对友好的提示
public R ExceptionHandler(HttpServletRequest req, Exception e) {
        log.error(String.format("Exception requestURI:%s", req.getRequestURI()), e);
        return ResultUtil.error(500, "服务器内部错误");
}

Пример кода GlobalExceptionHandler

Класс бизнес-исключений BusinessException

Класс бизнес-исключений определен для некоторых особых случаев. Этот класс наследует RuntimeException. Несколько типов бизнес-исключений также могут быть определены в сложном бизнесе. Некоторые логические исключения в бизнесе могут использоваться для создания этого бизнес-исключения, например, пароль проверки слова. Ошибка или значение поля превышает критический предел и т. д. Его можно использовать в сочетании с указанным выше классом ErrorCode, а код определения должен избегать некоторых системных предустановок.HTTP-код состояния Пример кода BusinessException

постскриптум

В этой статье в основном представлена ​​схема проектирования API в соответствии с методом Restful, спецификацией содержимого передачи, унифицированным классом возврата и унифицированным перехватом исключений.Используемый код был обновлен до github.easyDemo-validationВ проекте следующая статья поделится с вамиvalidationИспользование пакета проверки и советы по единой спецификации дизайна интерфейса приветствуются, чтобы начать и продолжать уделять внимание.