var s []int от s := []int{}?json.Marshal сериализует nil-слайс как JSON null, а инициализированный пустой слайс - как []. Для API и фронтенда это разная семантика.
var s1 []int
s2 := []int{}
json.Marshal(s1) // null
json.Marshal(s2) // []
Клиент может по-разному обрабатывать null (отсутствие поля/значения) и [] (пустой список). Чтобы гарантированно отдавать массив, инициализируйте слайс: s := []int{} или s := make([]int, 0).
json.Unmarshal в nil-слайс создаёт новый слайс при встрече []; при null слайс остаётся nil. Явная инициализация избавляет от неожиданностей.