Skip to content
forked from everytv/test2doc

Generate HTTP API documentation from your tests: a simple addition to Go's testing pkg

License

Notifications You must be signed in to change notification settings

chann-r/test2doc

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

99 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

test2doc

wercker status

Automatically generate HTTP API documentation from your Go unit tests: a simple addition to Go's testing pkg

Diving right in..

Given a handler func:

// GetWidget retrieves a single Widget
func GetWidget(w http.ResponseWriter, req *http.Request) {
	// get widget
	// respond with widget JSON
	// ...
}

And a test for this handler func:

func TestGetWidget(t *testing.T) {
	urlPath := fmt.Sprintf("/widgets/%d", 2)

	resp, err := http.Get(server.URL + urlPath)
	// assert all the things...
}

Test2doc will generate markdown documentation for this endpoint in the API Blueprint format, like so:

# Group widgets

## /widgets/{id}

+ Parameters
    + id: `2` (number)

### Get Widget [GET]
retrieves a single Widget

+ Response 200 

    + Body

            {
                "Id": 2,
                "Name": "Pencil",
                "Role": "Utensil"
            }        

Which you can then parse and host w/ Apiary.io, eg here. Or use a custom parser and host yourself.

screenshot


Things to note:

  1. Go pkg name becomes Group name
  2. Go handler name becomes endpoint title
  3. Go handler godoc string becomes endpoint description
  4. Everything else is recorded & interpreted directly from the requests and responses

Eg.

package widget

// GetWidget retrieves a single Widget
func GetWidget(w http.ResponseWriter, req *http.Request)

becomes

# Group widget

### Get Widget [*]
retrieves a single Widget

Installation

go get github.com/adams-sarah/test2doc/...


Integrating test2doc

Very few additions, and only to your testing code.

1. Add 3 things to your TestMain:

import (
	"github.com/adams-sarah/test2doc/test"
)

var server *test.Server

func TestMain(m *testing.M) {
	// 1. Tell test2doc how to get URL vars out of your HTTP requests
	//
	//    The 'URLVarExtractor' function must have the following signature:
	//      func(req *http.Request) map[string]string
	//      where the returned map is of the form map[key]value
	test.RegisterURLVarExtractor(myURLVarExtractorFn)


	// 2. You must use test2doc/test's wrapped httptest.Server instead of
	//    the raw httptest.Server, so that test2doc can listen to and
	//    record requests & responses.
	//
	//    NewServer takes your HTTP handler as an argument
	server, err := test.NewServer(router)
	if err != nil {
		panic(err.Error())
	}

	// .. then run your tests as usual
	// (remember that os.Exit does not respect defers)
	exitCode := m.Run()


	// 3. Finally, you must tell the wrapped server when you are done testing
	//    so that the buffer can be flushed to an apib doc file
	server.Finish()

	// note that os.Exit does not respect defers.
	os.Exit(exitCode)
}

Router-specific configurations

gorilla/mux configurations

	// NOTE: if you are using gorilla/mux, you must set the router's 
	//  'KeepContext' to true, so that url parameters can be accessed
	//  after the request has been handled.
	router := NewRouter()
	router.KeepContext = true
	
	// Use mux.Vars func as URLVarExtractor
	test.RegisterURLVarExtractor(mux.Vars)

julienschmidt/httprouter configurations

// MakeURLVarExtractor returns a func which extracts 
// url vars from a request for test2doc documentation generation
func MakeURLVarExtractor(router *httprouter.Router) parse.URLVarExtractor {
	return func(req *http.Request) map[string]string {
		// httprouter Lookup func needs a trailing slash on path
		path := req.URL.Path
		if !strings.HasSuffix(path, "/") {
			path += "/"
		}

		_, params, ok := router.Lookup(req.Method, path)
		if !ok {
			return nil
		}

		paramsMap := make(map[string]string, len(params))
		for _, p := range params {
			paramsMap[p.Key] = p.Value
		}

		return paramsMap
	}
}

// and then..
test.RegisterURLVarExtractor(MakeURLVarExtractor(router))

2. Combine the output .apib files

test2doc will spit out one doc file per package.

Eg. A package tree like:

.
├── foos
│   ├── foos.go
│   └── foos_test.go
└── widgets
    ├── widgets.go
    └── widgets_test.go

Will produce separate apib files, eg:

.
├── foos
│   ├── ...
│   └── foos.apib
└── widgets
    ├── ...
    └── widgets.apib

You will need to add the doc header (below) and combine all of the package doc files after your tests run.

eg.:

# find all *.apib files (after tests have run, generated files)
files=`find . -type f -name "*.apib"`

# copy template file to new apiary.apib file
cp apib.tmpl apiary.apib

# copy contents of each generated apib file into apiary.apib
# and delete the apib file
for f in ${files[@]}; do
	cat $f >> apiary.apib
	rm $f
done

where apib.tmpl includes the doc header information. Something like:

FORMAT: 1A
HOST: https://api.mysite.com

# The API for My Site

My Site is a fancy site. The API is also fancy.

About

Generate HTTP API documentation from your tests: a simple addition to Go's testing pkg

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 53.9%
  • API Blueprint 43.8%
  • Shell 2.3%