MCPcopy Index your code
hub / github.com/calvinmclean/babyapi

github.com/calvinmclean/babyapi @v0.34.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.34.0 ↗ · + Follow
481 symbols 1,641 edges 55 files 190 documented · 40% updated 58d agov0.34.0 · 2026-05-10★ 1342 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Baby API

GitHub go.mod Go version (subdirectory of monorepo) GitHub Workflow Status License Go Reference codecov

A Go CRUD API framework so simple a baby could use it. Now with MCP!

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 requests
  • Storage: set a different storage backend implementing the babyapi.Storage interface
  • AddCustomRoute: add more routes on the base API
  • Patch: add custom logic for handling PATCH 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

You can also opt to just use the api.Router() function to get the API's router/handler and add to your application's existing server.

Getting Started

  1. Create a new Go module:

shell mkdir babyapi-example cd babyapi-example go mod init babyapi-example

  1. Write main.go to create a TODO struct and initialize babyapi.API:

```go package main

import "github.com/calvinmclean/babyapi"

type TODO struct { babyapi.DefaultResource

   Title       string
   Description string
   Completed   bool

}

func main() { api := babyapi.NewAPI( "TODOs", "/todos", func() *TODO { return &TODO{} }, ) api.RunCLI() } ```

  1. Run!

shell go mod tidy go run main.go serve

  1. Use the built-in CLI to interact with the API:

```shell # Create a new TODO go run main.go client todos post --data '{"title": "use babyapi!"}'

# Get all TODOs go run main.go client todos list

# Get TODO by ID (use ID from previous responses) go run main.go client todos get cljvfslo4020kglbctog ```

Simple Example

Client

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.Search(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.

Testing

The babytest package provides some shortcuts and utilities for easily building table tests or simple individual tests. This allows seamlessly creating tests for an API using the convenient babytest.RequestTest struct, a function returning an *http.Request, or a slice of command-line arguments.

Check out some of the examples for examples of using the babytest package.

If your application uses api.RunCLI(), you can execute the generate-test command to generate a boilerplate CRUD test for the API:

go run main.go generate-test

Storage

You can bring any storage backend to babyapi by implementing the Storage interface. By default, the API will use the built-in KVStorage with the default configuration for in-memory map.

This storage implementation leverages tarmac-project/hord to support a variety of key-value store backends. Currently, the babyapi/storage/kv package provides helpers to create file or redis-based storage implementations.

db, err := kv.NewFileDB(hashmap.Config{
    Filename: "storage.json",
})
db, err := kv.NewRedisDB(redis.Config{
    Server: "localhost:6379",
})

api.SetStorage(babyapi.NewKVStorage[*TODO](db, "TODO"))

EndDateable

The babyapi.EndDateable interface can be implemented to enable soft-delete with the KVStorage. This will set an end-date instead of permanently deleting a resource. Then, deleting it again will permanently delete. Also, the Search implementation will filter out end-dated resources unless the end_dated query parameter is set to enable getting end-dated resources.

MCP

Babyapi uses mark3labs/mcp-go to implement a simple MCP Server for CRUD operations. This is also completely customizable with additional tools and options using the provided MCP functions.

MCP can simply be enabled like this:

api := babyapi.NewAPI("TODOs", "/todos", func() *TODO { return &TODO{} })

// Read only
api.EnableMCP(babyapi.MCPPermRead)
// Read and Create only
api.EnableMCP(babyapi.MCPPermRead | babyapi.MCPPermCreate)
// Enable all CRUD operations
api.EnableMCP(babyapi.MCPPermCRUD)

// Custom tools
api.AddMCPTools(...)

// Custom options
api.AddMCPServerOptions(
    server.WithInstructions("This is a web server for managing TODO list items"),
    ...,
)

// Custom HTTP options
api.AddMCPHTTPOptions(...)

Check out the simple TODO example and Nested API example!

I recommend testing with mark3labs/mcphost with a config like this:

mcpServers:
  todos:
    type: remote
    url: "${env://URL:-http://localhost:8080/mcp}"
    environment:
      DEBUG: "${env://DEBUG:-false}"
      LOG_LEVEL: "${env://LOG_LEVEL:-info}"

Extensions

babyapi provides an Extension interface that can be applied to any API with api.ApplyExtension(). Implementations of this interface create custom configurations and modifications that can be applied to multiple APIs. A few extensions are provided by the babyapi/extensions package:

  • HATEOAS: "Hypertext as the engine of application state" is the 3rd and final level of REST API maturity, making your API fully RESTful
  • KVStorage: provide a few simple configurations to use the KVStorage client with a local file or Redis
  • HTMX: HTMX expects 200 responses from DELETE requests, so this changes the response code

When to use babyapi

Like anything in software engineering, there are cases where babyapi is a good choice and others where it's not a great fit.

You should use babyapi if you: - Need a resource-driven REST HTTP API and want to get moving quickly. This can be a standalone application or a component of a larger application - Have multiple APIs that will interact and can benefit from a compatible client with no extra work - Want to learn about framework development and contribute to an open source project - Know the extent of the application's scope and know it won't grow beyond babyapi's capabilities

You should not use babyapi if you: - Need to have ultimate control over the application's execution that might not be compatible with babyapi (although maybe you can add support!) - Aren't willing to dig into the framework's code and learn how it works - Don't understand how to build an API without it. It's important to understand the fundamentals before taking shortcuts

If babyapi is not a great fit for your use-case, you can still use some of its features to speed up development! Check out the Use As Library example.

Examples

Description Features
TODO list This example expands upon the base example to create a realistic TODO list application
  • MCP example
  • <
  • Custom PATCH logic
  • Additional request validation
  • Automatically set CreatedAt field
  • Query parameter parsing to only show completed items
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
  • Nested API resources
  • Custom ResponseWrapper to add fields from related resources
  • HATEOAS Extension for hypermedia linking
Storage The example shows how to use the babyapi/storage package to implement persistent storage
  • Use SetStorage to use a custom storage implementation
  • Create a hord storage client using babyapi/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
  • Implement babyapi.HTMLer for HTML responses
  • Set custom HTTP response codes per HTTP method
  • Use built-in helpers for handling server-sent events on a custom route
  • Use SetOnCreateOrUpdate to do additional actions on create
  • Handle HTML forms as input instead of JSON (which works automatically and required no changes)
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
  • Demonstrates middlewares and nested resource relationships
  • Authentication
  • Custom non-CRUD endpoints
  • More complex HTML templating
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
  • Use NewRootAPI to create a root API
  • Add multiple children to create siblings

Extension points exported contracts — how you extend this code

HTMLer (Interface)
HTMLer allows for easily represending reponses as HTML strings when accepted content type is text/html [7 implementers]
router.go
Resource (Interface)
Resource is an interface/constraint used for API resources. In order to use API, you must have types that implement this [5 …
resource.go
Storage (Interface)
Storage defines how the API will interact with a storage backend [2 implementers]
storage.go
Extension (Interface)
Extension is a way that a collection of modifiers, or other code, can be applied to an API all at once. This makes code [2 …
extensions.go
EndDateable (Interface)
EndDateable allows soft-delete by setting an end-date on resources instead of deleting them [1 implementers]
end_date.go
PrintableResponse (Interface)
PrintableResponse allows CLI method to generically return a type that can be written to out
cli.go
RelatedAPI (Interface)
RelatedAPI declares a subset of methods from the API struct that are required to enable nested/parent-child API relation
related_apis.go
Test (Interface)
Test is an interface that allows executing different types of tests before running assertions
test/test_case.go

Core symbols most depended-on inside this repo

Run
called by 137
test/test_case.go
GetID
called by 100
resource.go
NewAPI
called by 53
babyapi.go
Error
called by 46
error.go
Get
called by 41
storage.go
AddNestedAPI
called by 24
related_apis.go
panicIfReadOnly
called by 24
babyapi.go
Search
called by 23
storage.go

Shape

Method 275
Function 115
Struct 69
Interface 12
TypeAlias 6
FuncType 4

Languages

Go100%

Modules by API surface

client.go48 symbols
babyapi_test.go37 symbols
babyapi.go31 symbols
resource.go27 symbols
examples/sql/main.go25 symbols
examples/event-rsvp/main.go22 symbols
related_apis.go20 symbols
mcp.go20 symbols
router.go17 symbols
helpers.go17 symbols
cli.go15 symbols
examples/sql/db/query.sql.go14 symbols

For agents

$ claude mcp add babyapi \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact