A Go HTTP client library for creating and sending API requests

Related tags

HTTP Clients sling
Overview

Sling Build Status Coverage GoDoc

Sling is a Go HTTP client library for creating and sending API requests.

Slings store HTTP Request properties to simplify sending requests and decoding responses. Check usage or the examples to learn how to compose a Sling into your API client.

Features

  • Method Setters: Get/Post/Put/Patch/Delete/Head
  • Add or Set Request Headers
  • Base/Path: Extend a Sling for different endpoints
  • Encode structs into URL query parameters
  • Encode a form or JSON into the Request Body
  • Receive JSON success or failure responses

Install

go get github.com/dghubble/sling

Documentation

Read GoDoc

Usage

Use a Sling to set path, method, header, query, or body properties and create an http.Request.

type Params struct {
    Count int `url:"count,omitempty"`
}
params := &Params{Count: 5}

req, err := sling.New().Get("https://example.com").QueryStruct(params).Request()
client.Do(req)

Path

Use Path to set or extend the URL for created Requests. Extension means the path will be resolved relative to the existing URL.

// creates a GET request to https://example.com/foo/bar
req, err := sling.New().Base("https://example.com/").Path("foo/").Path("bar").Request()

Use Get, Post, Put, Patch, Delete, Head, Options, Trace, or Connect which are exactly the same as Path except they set the HTTP method too.

req, err := sling.New().Post("http://upload.com/gophers")

Headers

Add or Set headers for requests created by a Sling.

s := sling.New().Base(baseUrl).Set("User-Agent", "Gophergram API Client")
req, err := s.New().Get("gophergram/list").Request()

Query

QueryStruct

Define url tagged structs. Use QueryStruct to encode a struct as query parameters on requests.

// Github Issue Parameters
type IssueParams struct {
    Filter    string `url:"filter,omitempty"`
    State     string `url:"state,omitempty"`
    Labels    string `url:"labels,omitempty"`
    Sort      string `url:"sort,omitempty"`
    Direction string `url:"direction,omitempty"`
    Since     string `url:"since,omitempty"`
}
githubBase := sling.New().Base("https://api.github.com/").Client(httpClient)

path := fmt.Sprintf("repos/%s/%s/issues", owner, repo)
params := &IssueParams{Sort: "updated", State: "open"}
req, err := githubBase.New().Get(path).QueryStruct(params).Request()

Body

JSON Body

Define JSON tagged structs. Use BodyJSON to JSON encode a struct as the Body on requests.

type IssueRequest struct {
    Title     string   `json:"title,omitempty"`
    Body      string   `json:"body,omitempty"`
    Assignee  string   `json:"assignee,omitempty"`
    Milestone int      `json:"milestone,omitempty"`
    Labels    []string `json:"labels,omitempty"`
}
githubBase := sling.New().Base("https://api.github.com/").Client(httpClient)
path := fmt.Sprintf("repos/%s/%s/issues", owner, repo)

body := &IssueRequest{
    Title: "Test title",
    Body:  "Some issue",
}
req, err := githubBase.New().Post(path).BodyJSON(body).Request()

Requests will include an application/json Content-Type header.

Form Body

Define url tagged structs. Use BodyForm to form url encode a struct as the Body on requests.

type StatusUpdateParams struct {
    Status             string   `url:"status,omitempty"`
    InReplyToStatusId  int64    `url:"in_reply_to_status_id,omitempty"`
    MediaIds           []int64  `url:"media_ids,omitempty,comma"`
}
tweetParams := &StatusUpdateParams{Status: "writing some Go"}
req, err := twitterBase.New().Post(path).BodyForm(tweetParams).Request()

Requests will include an application/x-www-form-urlencoded Content-Type header.

Plain Body

Use Body to set a plain io.Reader on requests created by a Sling.

body := strings.NewReader("raw body")
req, err := sling.New().Base("https://example.com").Body(body).Request()

Set a content type header, if desired (e.g. Set("Content-Type", "text/plain")).

Extend a Sling

Each Sling creates a standard http.Request (e.g. with some path and query params) each time Request() is called. You may wish to extend an existing Sling to minimize duplication (e.g. a common client or base url).

Each Sling instance provides a New() method which creates an independent copy, so setting properties on the child won't mutate the parent Sling.

const twitterApi = "https://api.twitter.com/1.1/"
base := sling.New().Base(twitterApi).Client(authClient)

// statuses/show.json Sling
tweetShowSling := base.New().Get("statuses/show.json").QueryStruct(params)
req, err := tweetShowSling.Request()

// statuses/update.json Sling
tweetPostSling := base.New().Post("statuses/update.json").BodyForm(params)
req, err := tweetPostSling.Request()

Without the calls to base.New(), tweetShowSling and tweetPostSling would reference the base Sling and POST to "https://api.twitter.com/1.1/statuses/show.json/statuses/update.json", which is undesired.

Recap: If you wish to extend a Sling, create a new child copy with New().

Sending

Receive

Define a JSON struct to decode a type from 2XX success responses. Use ReceiveSuccess(successV interface{}) to send a new Request and decode the response body into successV if it succeeds.

// Github Issue (abbreviated)
type Issue struct {
    Title  string `json:"title"`
    Body   string `json:"body"`
}
issues := new([]Issue)
resp, err := githubBase.New().Get(path).QueryStruct(params).ReceiveSuccess(issues)
fmt.Println(issues, resp, err)

Most APIs return failure responses with JSON error details. To decode these, define success and failure JSON structs. Use Receive(successV, failureV interface{}) to send a new Request that will automatically decode the response into the successV for 2XX responses or into failureV for non-2XX responses.

type GithubError struct {
    Message string `json:"message"`
    Errors  []struct {
        Resource string `json:"resource"`
        Field    string `json:"field"`
        Code     string `json:"code"`
    } `json:"errors"`
    DocumentationURL string `json:"documentation_url"`
}
issues := new([]Issue)
githubError := new(GithubError)
resp, err := githubBase.New().Get(path).QueryStruct(params).Receive(issues, githubError)
fmt.Println(issues, githubError, resp, err)

Pass a nil successV or failureV argument to skip JSON decoding into that value.

Modify a Request

Sling provides the raw http.Request so modifications can be made using standard net/http features. For example, in Go 1.7+ , add HTTP tracing to a request with a context:

req, err := sling.New().Get("https://example.com").QueryStruct(params).Request()
// handle error

trace := &httptrace.ClientTrace{
   DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
      fmt.Printf("DNS Info: %+v\n", dnsInfo)
   },
   GotConn: func(connInfo httptrace.GotConnInfo) {
      fmt.Printf("Got Conn: %+v\n", connInfo)
   },
}

req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
client.Do(req)

Build an API

APIs typically define an endpoint (also called a service) for each type of resource. For example, here is a tiny Github IssueService which lists repository issues.

const baseURL = "https://api.github.com/"

type IssueService struct {
    sling *sling.Sling
}

func NewIssueService(httpClient *http.Client) *IssueService {
    return &IssueService{
        sling: sling.New().Client(httpClient).Base(baseURL),
    }
}

func (s *IssueService) ListByRepo(owner, repo string, params *IssueListParams) ([]Issue, *http.Response, error) {
    issues := new([]Issue)
    githubError := new(GithubError)
    path := fmt.Sprintf("repos/%s/%s/issues", owner, repo)
    resp, err := s.sling.New().Get(path).QueryStruct(params).Receive(issues, githubError)
    if err == nil {
        err = githubError
    }
    return *issues, resp, err
}

Example APIs using Sling

Create a Pull Request to add a link to your own API.

Motivation

Many client libraries follow the lead of google/go-github (our inspiration!), but do so by reimplementing logic common to all clients.

This project borrows and abstracts those ideas into a Sling, an agnostic component any API client can use for creating and sending requests.

Contributing

See the Contributing Guide.

License

MIT License

Comments
  • Rework body handling to use providers

    Rework body handling to use providers

    Hi !

    Currently, sling only handles JSON, form and raw reader bodies. These 3 types are hard coded in the Sling struct, by having one field for every type.

    While it was still possible to send other types of bodies (xml, multipart, ...), their usage wasn't as fluent as the other 3 types.

    This PR proposes the following:

    • Introduce the BodyProvider interface
    • Rework the existing supported types to use the interface above
    • Add support for multipart and file upload using the same abstraction
    • Keep the existing shortcut body methods to not break clients

    Adding support for a new body types would not require touching the Sling struct. Simply a new implementation of the interface and maybe a factory function would do.

    Users wanting to handle other types can simply implement the BodyProvider and use the API as seamlessly as the baked-in types:

    sling.New().
            Post("http://localhost:4000/customer").
            BodyProvider(YamlBody(customer))
            ...
    

    The code in this PR is not finished (it could use some more polish and tests). I just wanted to get your feedback on this proposal before investing more time and effort on it.

    opened by jawher 6
  • Introduce response decoder interface

    Introduce response decoder interface

    I use Sling to get data from JSON APIs, soon I will have the use case to receive data from XML APIs, too. Hence I suggest a way that allows decoding responses from arbitrary sources:

    • Introduce a ResponseDecoder interface that abstracts away the actual decoding
    • Provide a default jsonDecoder that does what the library is doing at the moment: decoding from JSON (keep bc)
    • I also added a new test case, not sure if this is sufficient.
    • Documentation is missing for the new feature, I need to add this.

    Is there a chance of getting this merged?

    opened by maxbeutel 5
  • Allows plain body to be set, rather than just JSON or Form variables

    Allows plain body to be set, rather than just JSON or Form variables

    Hi Dalton,

    I wanted to use https://github.com/Jeffail/gabs with Sling, but found that you don't allow setting the body manually, only from an existing JSON-marshallable structure or form data. Here's a PR that allows you to manually set the body.

    I'm pretty new to Go, so if I've done anything daft feel free to let me know and I'll amend it.

    Cheers,

    Andy

    opened by andyjeffries 5
  • Add basic auth support: Sling.SetBasicAuth()

    Add basic auth support: Sling.SetBasicAuth()

    Sling is one of the nicest libraries I found, it's composable and elegant. However I found it frustrating that it lacked Basic Auth support which is a must have when writing API clients, so I thought I would add here.

    Tried to keep it as simple as possible and follow existing conventions (allow chaining etc ...)

    Let me know if you have any questions.

    opened by AaronO 4
  • Extend xml support

    Extend xml support

    Hi! Sling is a very nice api client builder and I like it a lot. But it would be nice to handle request/response in xml form too. I saw patch from @maxbeutel with ResponseDecoder and appreciate it. I suggest to extend it and add WithXMLResponse() method that will switch Sling to handle xml response and add BodyXML() method to send xml requests.

    opened by hardsky 3
  • Add Context support.

    Add Context support.

    Contexts are increasingly commonplace in the Go ecosystem, and it makes sense that a library meant to wrap the standard “net/http”.Request supports them without forcing the low-level Request and Do methods on you.

    Also, added Timeout as a convenience.

    opened by tcard 3
  • JSON body is not decoded when Content-Type: application/json is not present

    JSON body is not decoded when Content-Type: application/json is not present

    Thus, I think this is logical to decode JSON whether header is set or not, because user must explicitly pass successV/failureV.

    Broken test defines current behaviour, If you agree I will fix it too.

    opened by derlaft 3
  • Add Content-Length checking before decoding

    Add Content-Length checking before decoding

    We have a pattern with REST APIs at work where they return a 201 with a Location header for the new resource and an empty response body. Sling would attempt to decode the empty response body and return an EOF error.

    • Add a check before attempting to decode the response body to make sure that it's a non-zero Content-Length.
    • Update the tests to check that this specific case works
    • Update the GoDoc and comments
    opened by perigrin 2
  • Add support for response body decoders, including standard json and json protobuf

    Add support for response body decoders, including standard json and json protobuf

    Added a Decoder interface, default to JSON from encoding/json.

    Included a Protobuf JSON decoder using the gogo/protobuf/jsonpb marshaller as the first alternative.

    opened by codyaray 2
  • Save response body when parsing JSON

    Save response body when parsing JSON

    As the json decoder consumes the reader and there are cases where we want to preserve the response body to further process outside sling a flag to restore it has been included

    opened by jbcjorge 2
  • Add Sling.Safely()

    Add Sling.Safely()

    When safe mode is enabled, all Sling methods copy the underlying sling instance before mutating the Sling object effectively making Sling immutable.

    This is just a proof of concept to see whether it makes sense. It needs more documentation and testing before it's shippable, but I wanted to get feedback before doing that work.

    I think ultimately this mode would be inverted as 'unsafe mode' so that we do the least surprising thing by default and allow clients to opt-in to mutable state, but I've erred on the side of not changing existing behavior.

    opened by olix0r 2
  • Allow context aware requests

    Allow context aware requests

    Here we introduce RequestWithContext() and ReceiveWithContext() method which allow consumers to pass in a context. This is useful for working with HTTP requests where the consumer might want to control request lifetime via a context.

    opened by rsj-ioki 1
Releases(v1.4.1)
  • v1.4.1(Dec 7, 2022)

  • v1.4.0(Oct 2, 2021)

  • v1.3.0(Jul 8, 2019)

    • Add Sling ResponseDecoder setter for receiving responses with a custom ResponseDecoder (#49)
    • Add Go module support (i.e. go.mod). Exclude examples (multi-module). (#52)
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Nov 18, 2018)

  • v1.1.0(Dec 18, 2016)

    • Allow JSON decoding, regardless of response Content-Type (#26)
    • Add BodyProvider interface and setter so request Body encoding can be customized (#23)
    • Add Doer interface and setter so request sending behavior can be customized (#21)
    • Add SetBasicAuth setter for Authorization headers (#16)
    • Add Sling Body setter to set an io.Reader on the Request (#9)
    Source code(tar.gz)
    Source code(zip)
  • v1.0(May 23, 2015)

    • Added support for receiving and decoding error JSON structs
    • Renamed Sling JsonBody setter to BodyJSON (breaking)
    • Renamed Sling BodyStruct setter to BodyForm (breaking)
    • Renamed Sling fields httpClient, method, rawURL, and header to be internal (breaking)
    • Changed Do and Receive to skip response JSON decoding if "application/json" Content-Type is missing
    • Changed Sling.Receive(v interface{}) to Sling.Receive(successV, failureV interface{}) (breaking)
      • Previously Receive attempted to decode the response Body in all cases
      • Updated Receive will decode the response Body into successV for 2XX responses or decode the Body into failureV for other status codes. Pass a nil successV or failureV to skip JSON decoding into that value.
      • To upgrade, pass nil for the failureV argument or consider defining a JSON tagged struct appropriate for the API endpoint. (e.g. s.Receive(&issue, nil), s.Receive(&issue, &githubError))
      • To retain the old behavior, duplicate the first argument (e.g. s.Receive(&tweet, &tweet))
    • Changed Sling.Do(http.Request, v interface{}) to Sling.Do(http.Request, successV, failureV interface{}) (breaking)
      • See the changelog entry about Receive, the upgrade path is the same.
    • Removed HEAD, GET, POST, PUT, PATCH, DELETE constants, no reason to export them (breaking)
    Source code(tar.gz)
    Source code(zip)
  • v0.4(May 23, 2015)

  • v0.3(May 23, 2015)

    • Added BodyStruct method for setting a url encoded form body on the Request
    • Added Add and Set methods for adding or setting Request Headers
    • Added JsonBody method for setting JSON Request Body
    • Improved examples and documentation
    Source code(tar.gz)
    Source code(zip)
  • v0.2(May 23, 2015)

    • Added http.Client setter
    • Added Sling.New() method to return a copy of a Sling
    • Added Base setter and Path extension support
    • Added method setters (Get, Post, Put, Patch, Delete, Head)
    • Added support for encoding URL Query parameters
    • Added example tiny Github API
    • Changed v0.1.0 method signatures and names (breaking)
    • Removed Go 1.0 support
    Source code(tar.gz)
    Source code(zip)
  • v0.1(May 23, 2015)

Owner
Dalton Hubble
Friends with the machines | Kubernetes | @poseidon Typhoon and Matchbox | Previously @lyft, @coreos, @twitter, MIT
Dalton Hubble
go http api to handle phishing resources requests

go http api to handle phishing resources requests (auth check, prometheus metrics, pushing to rabbit, logging to elasticsearch)

Dmitry Karpov 0 Oct 8, 2021
This is a simple single-host reverse proxy that intercept and save HTTP requests and responses

HTTP Telescope Debug HTTP requests using a reverse proxy. Description This is a simple single-host reverse proxy that intercept and save HTTP requests

Enrico 3 Mar 20, 2022
Replacement of ApacheBench(ab), support for transactional requests, support for command line and package references to HTTP stress testing tool.

stress stress is an HTTP stress testing tool. Through this tool, you can do a stress test on the HTTP service and get detailed test results. It is ins

Wenjia Xiong 37 Aug 23, 2022
A golang tool which makes http requests and prints the address of the request along with the MD5 hash of the response.

Golang Tool This repository is a golang tool which makes http requests to the external server and prints the address of the request along with the MD5

null 0 Oct 17, 2021
Gourl: Performs (multiple) HTTP requests and gathers stats

Gourl: Performs (multiple) HTTP requests and gathers stats

Maxime Le Conte des Floris 0 Mar 9, 2022
Nap is a file-based framework for automating the execution of config-driven HTTP requests and scripts.

Nap Nap is a file-based framework for automating the execution of config-driven HTTP requests and scripts. Installation Options Using go get $ go inst

Dave Sheldon 14 Nov 17, 2022
Http client call for golang http api calls

httpclient-call-go This library is used to make http calls to different API services Install Package go get

pzenteno 16 Oct 7, 2022
This project aims for printing HTTP requests from outside simply

HTTP Debug Server This project aims for printing HTTP requests from outside simp

John Niang 1 Jan 29, 2022
A Go "clone" of the great and famous Requests library

GRequests A Go "clone" of the great and famous Requests library License GRequests is licensed under the Apache License, Version 2.0. See LICENSE for t

Levi Gross 1.9k Dec 23, 2022
fhttp is a fork of net/http that provides an array of features pertaining to the fingerprint of the golang http client.

fhttp The f stands for flex. fhttp is a fork of net/http that provides an array of features pertaining to the fingerprint of the golang http client. T

Flexagon 61 Jan 1, 2023
Simple HTTP and REST client library for Go

Resty Simple HTTP and REST client library for Go (inspired by Ruby rest-client) Features section describes in detail about Resty capabilities Resty Co

Go Resty 7.1k Jan 1, 2023
Gotcha is an high level HTTP client with a got-like API

Gotcha is an alternative to Go's http client, with an API inspired by got. It can interface with other HTTP packages through an adapter.

Sleeyax 20 Dec 7, 2022
Cake is a lightweight HTTP client library for GO, inspired by Java Open-Feign.

Cake is a lightweight HTTP client library for GO, inspired by Java Open-Feign. Installation # With Go Modules, recommanded with go version > 1.16

snown 8 Oct 6, 2022
retryablehttp package provides a familiar HTTP client interface with automatic retries and exponential backoff.

retryablehttp package provides a familiar HTTP client interface with automatic retries and exponential backoff.

HashiCorp 1.4k Jan 4, 2023
Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http

fasthttp Fast HTTP implementation for Go. Currently fasthttp is successfully used by VertaMedia in a production serving up to 200K rps from more than

Aliaksandr Valialkin 18.9k Jan 2, 2023
Speak HTTP like a local. (the simple, intuitive HTTP console, golang version)

http-gonsole This is the Go port of the http-console. Speak HTTP like a local Talking to an HTTP server with curl can be fun, but most of the time it'

mattn 65 Jul 14, 2021
NATS HTTP Round Tripper - This is a Golang http.RoundTripper that uses NATS as a transport.

This is a Golang http.RoundTripper that uses NATS as a transport. Included is a http.RoundTripper for clients, a server that uses normal HTTP Handlers and any existing http handler mux and a Caddy Server transport.

R.I.Pienaar 81 Dec 6, 2022
Simple HTTP package that wraps net/http

Simple HTTP package that wraps net/http

Kris 0 Jan 17, 2022