Since you can always instantiate a button from storyboard, that button need to have a required init?(coder aDecoder: NSCoder). That method is required just for you to insert a button in the storyboard.
If the button is actually created via storyboard, than of course it won't have the id soon enough (at init time) for it not to be optional.
Since I assume that you will always instantiate the button programmatically, and not via storyboard, you can just implement your own init, with your params, and than, in the required init, just insert a fatalError.
That will compile as the fatalError returns Never (meaning it never returns), so the compiler can understand that bookId will never actually be nil.
Actually if you delete the required init Xcode will suggest you to insert the method with a fatalError and will autocomplete it for you if you want.
Of course, after that, if you put a button of this class in the storyboard, it will crash, so don't do that.
Adding a property to a button (or view in general) and force it to be created via some init and not via storyboard, in general, is perfectly fine if you don't intend to use the storyboard for that button (or view).
PS: after this brief on how to do what you want to do, I want to suggest you NOT to do it in THIS case, as it seems a bad idea for a button to hold any sort of data about some API you need to call. The button should just be a button and inform you when the user taps it. Then, when the button is pressed, some other class should handle what to do, using some other model to get the correspondent bookId for that button tap.
Completely different was if you would add some property that helped the button to look different, or add some other behavior specific to the use of the button (which is just be tappable and inform of taps)