It really depends on what AddPermission should do when it already exists? Should it overwrite existing? Should it fail? Should I do nothing?
– EuphoricDec 6 at 14:29

@Euphoric there is nothing to overwrite, because it should act more like Dictionary, so preferably it should do nothing or at least indicate that something already exists similarly to how Dictionary does it.
– KonradDec 6 at 14:31

You might be interested in the Tell, Don't Ask principle. Ultimately, it depends on the kind of API you want, but as a rule of thumb, I would follow this principle. Note that your first version may have concurrency issues, so it might be worth taking this into account.
– Vincent SavardDec 6 at 16:53

Its usually best if the API is written so that the check itself is internal, but it depends on what the behaviour you want from both the API and the caller.

Hide it all behind the API where caller shouldn't really care and its more of an internal implementation thing
Permission has no other properties: addPermission(user, 'somePermission')
And we are ok if this call just creates the permission entry (some sort of flexible admin schema)

throw an exception if the caller must have done something else first (eg, set permissions which shouldn't be under program control)
Permission can't be added dynamically try {addPermission(user, 'somePermission') } catch e(){alert ("permission doesn't exist")}

Provide an override method if you want the caller to optionally ask the API to do the job on their behalf (and presuming this is practical for the API to do for them)addPermission(user, 'somePermission', addIfMissing=true)
Again, we have to be ok if this call just creates the permission entry

If additional properties are required for the precursor then expose extra methods for the caller to create the thing.
If you don't expose an existence check then the caller should implement a try/catch around the main method call just in case they need to make the precursor call. Better to expose the existence check as well so they can make it obvious in their code:

Some callers will want to use HasPermission() to validate assumptions before continuing with a long or expensive transaction — or to otherwise validate assumptions or debug. This method should be more accessible than AddPermission() to support those workflows.

However, if a client chooses to call AddPermission() without checking for existence first, don't force them catch exceptions or differentiate between types of success. And to that end, return a response object that can communicate the nuanced success and failure modes. Something like: