This is more of a cryptography question than a Rust question, but typically you'll use a so-called key diversification function (KDF) for this. See: https://en.wikipedia.org/wiki/Key_derivation_function (another term for the same thing, with slightly different connotations).
For an API key, you might have a user ID sent in the clear, and a secret key SK on the server. The KDF you would use would be something like HMAC-SHA256 truncated to 128 bits. Then the API key would be KDF(SK, ID). You will want a way to invalidate ID's and issue new ones so the person can cycle or change their API key. You could add a parameter P to the UID for this purpose, but again you have to be able to invalidate it.
You want to be very careful with SK on the server side. In financial apps (where the key can steal real money) you'd encapsulate it in a hardware security module (HSM). For less high-value apps you could still wrap it in its own HSM-like interface in its own process, that the rest of the app queries through a local socket. The idea is that the KDF process has a smaller attack surface than the big complicated web app. It can also implement throttling (limit the number of queries per second) in case a compromise app starts trying to spew API keys, and so on.
Added: your idea of just generating keys randomly and storing them in the database is also ok, but again you have to pay some attention to security, dealing with the possibility of the key table spilling, etc.