go 28 lines · 6 steps

Streaming video files with Gin

A Gin handler that looks up a video, opens its file, and streams it with range support via http.ServeContent.

Explained by highlit
1func ServeVideo(c *gin.Context) {
2 id := c.Param("id")
3 video, err := videoRepo.FindByID(c.Request.Context(), id)
4 if err != nil {
5 c.JSON(http.StatusNotFound, gin.H{"error": "video not found"})
6 return
7 }
8 
9 path := filepath.Join(mediaRoot, video.StoredName)
10 info, err := os.Stat(path)
11 if err != nil || info.IsDir() {
12 c.JSON(http.StatusNotFound, gin.H{"error": "file unavailable"})
13 return
14 }
15 
16 f, err := os.Open(path)
17 if err != nil {
18 c.JSON(http.StatusInternalServerError, gin.H{"error": "could not open file"})
19 return
20 }
21 defer f.Close()
22 
23 c.Header("Accept-Ranges", "bytes")
24 c.Header("Content-Type", video.ContentType)
25 c.Header("Cache-Control", "public, max-age=86400")
26 
27 http.ServeContent(c.Writer, c.Request, video.StoredName, info.ModTime(), f)
28}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Delegating to http.ServeContent gets you range requests, conditional GETs, and content-type handling for free.
  2. 2Validate the database record and the file on disk separately, since either can be missing independently.
  3. 3Defer closing the file right after opening so the handle is released on every return path.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Streaming video files with Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code