Поддерживаю обоих, слать код в теле ответа говно, слать код хттп-статусом тоже говно, потому что более уебанского протокола не существует (в качестве разминки для мозгов можете попробовать посчитать какое количество из 4хх реально являются ошибками).
Лично я за то чтобы использовать хттп максимум как транспорт, хоть он и выше уровнем.
Меня видимо ни один из оппонентов этого спора не понял... Я не говорю, что код ошибки нужно слать только как http статус. Имхо, исход каждой операции представленной http api можно классифицировать как успех (код 2хх), ошибка валидации (422 unprocessable entity), нарушение инварианта какого то объекта или агрегата (те самые ошибки БЛ, 409 conflict), либо же необработанные исключения (500). Этот список не включает коды типа 415, или 400, которые соответствуют неподдерживаевому формату сообщения в запросе. Я не настаиваю на том, что эти категории ошибок должны иметь разные статус коды, можно обойтись одним, отличным от 2хх.
Теперь, каждый неуспешный исход операции по-хорошему включает тело содержащее минимум 2 поля: код ошибки и текст ошибки. При этом, например ошибки валидации могут иметь дополнительные поля, типа массива полей или коллекций полей, значения которых не валидны.