Independent from implementing a key-value-store or whatever: you could use HATEOAS to describe your api. This enrichens the plain ressource information with meta-information what to do with your API. So in your example a call to base gives a collection of keys and their values:
GET /baseurl/
gives you a resultset:
[
{
"links": {
"self": {
"href": "http://www.yoursite/base"
},
"item": [
{
"href": "http://www.yoursite/base/key1"
},
{
"href": "http://www.yoursite/base/key2"
},
{
"href": "http://www.yoursite/base/key3"
}
]
},
"content": [
{
"key": "key1",
"value": "value1",
"links": [
{
"self": {
"href": "http://www.yoursite/base/key1"
}
}
]
},
{
"key": "key2",
"value": "value2",
"links": [
{
"self": {
"href": "http://www.yoursite/base/key2"
}
}
]
},
{
"key": "key3",
"value": "value3",
"links": [
{
"self": {
"href": "http://www.yoursite/base/key3"
}
}
]
}
]
}
]
A simple GET against your baseurl shows a list of items returned. Each with a link (at least) to the single item (or more if you want to relate several keys to other ressources). From that I - as a consumer - know, that there is a ressource key3 behind the URL http://www.yoursite/base/key3. Analogous I know, that I (eventually) could use the typical HTTP-verbs (HEAD, GET,PUT,POST,DELETE, PATCH). But I can query that ressurce for its capabilities via an OPTIONS-Request. Its answer would contain an Allow-Section, which shows allowed verbs:
Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE
When implemented in this way, your API becomes very intuitive and selfexplaining (independend from the ressources you offer).