A Go CRUD API framework so simple a baby could use it.
babyapi
is a super simple framework that automatically creates an HTTP API for create, read, update, and delete operations on a struct. Simply extend the babyapi.DefaultResource
type to get started.
Implement custom request/response handling by implemented Renderer
and Binder
from go-chi/render
. Use provided extension functions to add additional API functionality:
OnCreateOrUpdate
: additional handling for create/update requestsStorage
: set a different storage backend implementing thebabyapi.Storage
interfaceAddCustomRoute
: add more routes on the base APIPatch
: add custom logic for handlingPATCH
requests- And many more! (see examples and docs)
- Override any of the default handlers and use
babyapi.Handler
shortcut to easily render errors and responses
- Create a new Go module:
mkdir babyapi-example cd babyapi-example go mod init babyapi-example
- Write
main.go
to create aTODO
struct and initializebabyapi.API
:package main import "github.com/calvinmclean/babyapi" type TODO struct { babyapi.DefaultResource Title string Description string Completed bool } func main() { api := babyapi.NewAPI[*TODO]( "TODOs", "/todos", func() *TODO { return &TODO{} }, ) api.RunCLI() }
- Run!
go mod tidy go run main.go serve
- Use the built-in CLI to interact with the API:
# Create a new TODO go run main.go post TODOs '{"title": "use babyapi!"}' # Get all TODOs go run main.go list TODOs # Get TODO by ID (use ID from previous responses) go run main.go get TODOs cljvfslo4020kglbctog
In addition to providing the HTTP API backend, babyapi
is also able to create a client that provides access to the base endpoints:
// Create a client from an existing API struct (mostly useful for unit testing):
client := api.Client(serverURL)
// Create a client from the Resource type:
client := babyapi.NewClient[*TODO](addr, "/todos")
// Create a new TODO item
todo, err := client.Post(context.Background(), &TODO{Title: "use babyapi!"})
// Get an existing TODO item by ID
todo, err := client.Get(context.Background(), todo.GetID())
// Get all incomplete TODO items
incompleteTODOs, err := client.GetAll(context.Background(), url.Values{
"completed": []string{"false"},
})
// Delete a TODO item
err := client.Delete(context.Background(), todo.GetID())
The client provides methods for interacting with the base API and MakeRequest
and MakeRequestWithResponse
to interact with custom routes. You can replace the underlying http.Client
and set a request editor function that can be used to set authorization headers for a client.
babyapi
also makes it easy to unit test your APIs with functions that start an HTTP server with routes, execute the provided request, and return the httptest.ResponseRecorder
.
You can bring any storage backend to babyapi
by implementing the Storage
interface. By default, the API will use the built-in MapStorage
which just uses an in-memory map.
The babyapi/storage
package provides another generic Storage
implementation using madflojo/hord
to support a variety of key-value store backends. babyapi/storage
provides helper functions for initializing the hord
client for Redis or file-based storage.
db, err := storage.NewFileDB(hashmap.Config{
Filename: "storage.json",
})
db, err := storage.NewRedisDB(redis.Config{
Server: "localhost:6379",
})
api.SetStorage(storage.NewClient[*TODO](db, "TODO"))
Description | Features | |
---|---|---|
TODO list | This example expands upon the base example to create a realistic TODO list application |
|
Nested resources | Demonstrates how to build APIs with nested/related resources. The root resource is an Artist which can have Albums and MusicVideos . Then, Albums can have Songs |
|
Storage | The example shows how to use the babyapi/storage package to implement persistent storage |
|
TODO list with HTMX UI | This is a more complex example that demonstrates an application with HTMX frontend. It uses server-sent events to automatically update with newly-created items |
|
Event RSVP | This is a more complex nested example that implements basic authentication, middlewares, and relationships between nested types. The app can be used to create Events and provide guests with a link to view details and RSVP |
|
Multiple APIs | This example shows how multiple top-level (or any level) sibling APIs can be served, and have CLI functionality, under one root API |
|
Also see a full example of an application implementing a REST API using babyapi
in my automated-garden
project.
Please open issues for bugs or feature requests and feel free to create a PR.