make defapi into a macro so it can capture opts