Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →To build an API with Go, create a module, define resource-shaped endpoints, decode and encode JSON, return deliberate HTTP status codes, and connect handlers to persistent storage. The smallest useful example can run with either the Gin framework or Go 1.22+ net/http. Start with an in-memory service to understand the request flow, then replace that slice with a database and add the operational controls your application requires.
What you will build
This tutorial creates an album API with three endpoints:
| Method | Path | Purpose | Success response |
|---|---|---|---|
| GET | /albums | List all albums | 200 with a JSON array |
| POST | /albums | Create an album | 201 with the created object |
| GET | /albums/{id} | Fetch one album | 200 with an object, or 404 |
The data is held in memory so the example stays focused. It disappears when the process stops; a real application normally reads and writes a database.
Prerequisites and project setup
- Install a current Go toolchain. The standard-library routing used later requires Go 1.22 or newer.
- Know basic Go syntax, structs, slices, pointers, and error handling.
- Have
curlor another HTTP client for testing.
- Create a directory and initialize a module (replace the module path with your repository path):
mkdir go-albums cd go-albums go mod init example.com/go-albums - If using Gin, add it to the module:
go get github.com/gin-gonic/gin - Create
main.go, then run the server withgo run ..
Define the resource and API contract
Use a JSON-friendly struct and stable field names. Keep the identifier as a string at the HTTP boundary so clients do not depend on an internal numeric type.
Recommended Free Tools
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
type album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
type createAlbum struct {
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
Decide validation rules before writing handlers: title and artist are required, price must not be negative, and an unknown ID is a 404. Returning consistent JSON errors makes clients easier to write.
Build the API with Gin
Gin is the framework used by the official Go REST tutorial. It supplies route matching, JSON binding, and response helpers while leaving your application logic in ordinary Go functions.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type album struct {
ID string `json:"id"`
Title string `json:"title"`
Artist string `json:"artist"`
Price float64 `json:"price"`
}
type createAlbum struct {
Title string `json:"title" binding:"required"`
Artist string `json:"artist" binding:"required"`
Price float64 `json:"price" binding:"gte=0"`
}
var albums = []album{
{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
}
func listAlbums(c *gin.Context) {
c.JSON(http.StatusOK, albums)
}
func createAlbumHandler(c *gin.Context) {
var input createAlbum
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
nextID := "3" // Replace with a database-generated ID in a real service.
created := album{ID: nextID, Title: input.Title, Artist: input.Artist, Price: input.Price}
albums = append(albums, created)
c.JSON(http.StatusCreated, created)
}
func getAlbum(c *gin.Context) {
id := c.Param("id")
for _, a := range albums {
if a.ID == id {
c.JSON(http.StatusOK, a)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "album not found"})
}
func main() {
router := gin.Default()
router.GET("/albums", listAlbums)
router.POST("/albums", createAlbumHandler)
router.GET("/albums/:id", getAlbum)
router.Run(":8080")
}
Run it with go run .. Gin listens on port 8080. In a second terminal:
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
curl http://localhost:8080/albums
curl http://localhost:8080/albums/1
curl -i -X POST http://localhost:8080/albums
-H 'Content-Type: application/json'
-d '{"title":"Kind of Blue","artist":"Miles Davis","price":39.99}'
The POST should return 201. Malformed JSON or a missing required field returns 400; an absent ID returns 404.
Preventing duplicate IDs
The fixed nextID is intentionally educational and will collide after the first creation. In production, let the database generate a primary key or use a collision-resistant ID generator. Also protect shared in-memory state with synchronization if handlers can write concurrently; a database transaction is the usual durable solution.
Use Go 1.22+ net/http instead of a framework
Go 1.22 added method matching and wildcard segments to http.ServeMux. A wildcard can be read with Request.PathValue. The Go team describes this as “one fewer dependency for many projects,” while noting that third-party frameworks remain appropriate for advanced routing needs.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type album struct { ID string `json:"id"`; Title string `json:"title"`; Artist string `json:"artist"`; Price float64 `json:"price"` }
var albums = []album{{"1", "Blue Train", "John Coltrane", 56.99}}
func writeJSON(w http.ResponseWriter, status int, value any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(value)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /albums", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, albums) })
mux.HandleFunc("GET /albums/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
for _, a := range albums { if a.ID == id { writeJSON(w, http.StatusOK, a); return } }
writeJSON(w, http.StatusNotFound, map[string]string{"error": "album not found"})
})
mux.HandleFunc("POST /albums", func(w http.ResponseWriter, r *http.Request) {
var input album
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&input); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"}); return }
input.ID = fmt.Sprintf("%d", len(albums)+1)
albums = append(albums, input)
writeJSON(w, http.StatusCreated, input)
})
log.Println("listening on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
Choose net/http when method-and-path routing plus your own middleware is enough. Choose Gin (or another framework) when you need its binding, middleware ecosystem, grouping, or more elaborate routing abstractions. Go 1.22 routing removes a dependency; it does not remove every reason to use a framework.
JSON, validation, and HTTP behavior
Decode safely
Use a request-specific input struct instead of decoding directly into a persistence model. Set a body limit with http.MaxBytesReader in a standard-library handler, reject trailing JSON values when strictness matters, and close request bodies that you open yourself.
Return predictable statuses
- 200 OK: successful reads and updates that return a representation.
- 201 Created: successful creation; include the representation and, where useful, a
Locationheader. - 204 No Content: successful deletion or an update with no response body.
- 400 Bad Request: malformed JSON or invalid field values.
- 404 Not Found: the route or resource does not exist.
- 409 Conflict: a uniqueness or state conflict.
- 500 Internal Server Error: an unexpected server failure; do not expose stack traces or database details.
Keep errors machine-readable
Use one shape, such as {"error":"album not found"}, across handlers. Log the detailed cause on the server while returning a safe message to the client.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
Replace the slice with persistent storage
The official Gin example explicitly treats its slice as a simplification; a typical API interacts with a database. Create a repository layer so handlers depend on methods such as ListAlbums, FindAlbum, and CreateAlbum, not SQL strings. Open a connection pool at startup, configure its limits and lifetime, use context-aware queries, and close the pool during graceful shutdown. Wrap multi-step writes in transactions and map “no rows” to 404 rather than 500. Keep migrations versioned with the application.
Run and test the service
- Format and compile:
gofmt -w .thengo test ./.... - Run locally with
go run .and exercise every success and error path usingcurl. - Add table-driven unit tests for validation and handler responses. Use
httptestto test without opening a real port. - Add integration tests against a disposable database before relying on repository behavior.
Keep configuration such as the listen address, database URL, and logging level in environment variables or a configuration object rather than hard-coding secrets.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Production concerns the small example does not solve
An API is not production-ready merely because it returns JSON. Define authentication and authorization separately: identifying a caller is not the same as deciding what that caller may do. Enforce TLS at the deployment boundary, validate and bound every input, apply request timeouts, and decide how rate limiting and pagination fit your traffic. Add structured logs, metrics, traces, health endpoints, and alerts appropriate to your service. The tutorial sources establish the implementation path, not a complete security or operations checklist, so document these decisions for your environment and threat model.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Graceful shutdown
Use an http.Server with read, write, and idle timeouts. On shutdown, stop accepting new requests, give in-flight requests a bounded grace period, then close database resources. This prevents deploys from cutting off active clients.
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
404 for a valid-looking URL |
Method or path pattern does not match. | Check the HTTP verb, leading slash, wildcard name, and Go version when using ServeMux. |
400 on a POST |
Invalid JSON, wrong content type, or missing required field. | Send Content-Type: application/json and validate the exact payload. |
| Server exits immediately | ListenAndServe or router.Run returned an error. |
Log the returned error; check whether port 8080 is already occupied. |
| New records vanish | Storage is the demonstration slice. | Persist records in a database and load them on startup. |
| Duplicate IDs under load | IDs are generated from slice length. | Use a database sequence or collision-resistant IDs. |
| Data races reported by tests | Concurrent handlers mutate shared memory. | Run go test -race ./...; add synchronization or move writes to a transactional store. |
Or skip the browser setup
If your next task is generating screenshots of API documentation, status pages, or test fixtures, ScreenshotNeo provides a single HTTP call instead of maintaining browser automation. It accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for options such as full-page capture, CSS or JavaScript, device presets, PDF output, request blocking, custom headers and cookies, signed links, asynchronous webhooks, and bulk capture. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
Further client examples
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
Frequently Asked Questions
Should a new Go API start with Gin or net/http?
Use net/http when method-and-path routing is sufficient; use Gin when its binding, middleware, grouping, or broader framework abstractions provide value. Both are valid choices.
Why does my in-memory API lose data after a restart?
The sample stores records in a process-local slice. Replace that slice with a database-backed repository for durable data.
What Go version supports wildcard values in ServeMux?
Go 1.22 introduced method patterns, wildcard path segments, and Request.PathValue in the standard router.
The Bottom Line
A sound Go API begins with a small, tested contract and clear handlers, then grows behind repository, validation, authentication, observability, and deployment boundaries. Use Gin for convenient framework features or Go 1.22+ net/http for a dependency-light router, but do not mistake the in-memory tutorial for a production architecture.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

