Skip to content

Conversation

@itssimon
Copy link
Contributor

@itssimon itssimon commented May 14, 2025

This PR adds a Monitoring with Apitally recipe that demonstrates how to easily add monitoring and request logging to any Go Fiber application with Apitally.

Apitally is a simple, lightweight API monitoring & analytics tool. It offers real-time insights into API usage, performance, and errors – without requiring complex setup or any extra infrastructure. The official Apitally middleware for Fiber can be integrated in just a few lines of code.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a REST API server for managing books, featuring API key authentication and request validation.
    • Integrated monitoring and request logging with Apitally, including detailed insights and error tracking.
    • Added endpoints to retrieve and create book records.
  • Documentation

    • Added a comprehensive README with setup instructions, API usage examples, and monitoring dashboard details.
    • Updated main README to include a new "Monitoring with Apitally" section linking to the detailed documentation.

@welcome
Copy link

welcome bot commented May 14, 2025

Thanks for opening this pull request! 🎉 Please check out our contributing guidelines.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 14, 2025

Walkthrough

A new REST API server written in Go using the Fiber framework has been introduced, featuring API key authentication and integrated request monitoring/logging with Apitally. Accompanying documentation in a README file provides setup instructions, usage guidance, and an overview of the monitoring features and endpoints.

Changes

File(s) Change Summary
monitoring-with-apitally/main.go Added a Go program implementing a Fiber-based REST API with API key authentication and Apitally monitoring, including request validation and detailed logging.
monitoring-with-apitally/README.md Added documentation detailing setup, usage, API endpoints, API key configuration, and Apitally dashboard features with a screenshot.
README.md Added a new entry linking to the "Monitoring with Apitally" README in the main README table of contents.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FiberServer
    participant Apitally
    Client->>FiberServer: HTTP Request with API Key
    FiberServer->>FiberServer: Validate API Key
    alt Valid Key
        FiberServer->>Apitally: Log Request (with user info)
        alt GET /v1/books
            FiberServer-->>Client: Return list of books
        else POST /v1/books
            FiberServer->>FiberServer: Validate JSON body
            alt Validation Error
                FiberServer->>Apitally: Log Validation Error
                FiberServer-->>Client: 400 Bad Request
            else Success
                FiberServer-->>Client: 201 Created
            end
        end
    else Invalid Key
        FiberServer-->>Client: 401 Unauthorized
    end
Loading

Suggested reviewers

  • ReneWerner87

Poem

In a burrow of Go and Fiber delight,
Apitally watches each API flight.
Keys unlock books, requests are tracked,
Logs and dashboards keep all on track.
With headers and hashes, the rabbits cheer—
Monitoring magic, the code is clear!
🐇📚✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb88b9f and 2649352.

📒 Files selected for processing (1)
  • README.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • README.md

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (9)
monitoring-with-apitally/README.md (4)

13-15: Prerequisites section could be more specific.

While mentioning Golang installation is necessary, it would be helpful to specify a minimum required version of Go, especially if any newer language features are used in the code.

-Ensure you have Golang installed.
+Ensure you have Golang installed (version 1.16 or later).

47-49: API key exposed in curl example.

The API key is included in the curl example. While this is a sample key for demonstration purposes, it's good practice to avoid including API keys in documentation, even sample ones.

-curl -X GET -H "Authorization: Bearer d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4" http://localhost:3000/v1/books
+curl -X GET -H "Authorization: Bearer YOUR_API_KEY" http://localhost:3000/v1/books
🧰 Tools
🪛 Gitleaks (8.21.2)

48-48:

(curl-auth-header)


51-56: Dashboard section could include more detail about Apitally features.

The dashboard section briefly mentions the features but could be enhanced with more specifics about what metrics are available and how they can be used to improve API development and operations.

 The Apitally dashboard will show the requests you've made to the API.

-It provides detailed insights into the API's usage, errors, and performance. Individual requests can be inspected in the request log. You can also set up custom alerts.
+It provides detailed insights into the API's usage, errors, and performance, including:
+
+- Request volumes and response times
+- Error rates and status code distribution
+- Endpoint popularity and usage patterns
+- Detailed request/response inspection in the request log
+- Custom alerts for error spikes or performance degradation

57-57: Consider adding alt text to the screenshot.

For improved accessibility, consider adding more descriptive alt text to the screenshot image.

-![Apitally screenshots](https://assets.apitally.io/screenshots/overview.png)
+![Apitally dashboard showing API metrics, request logs, and monitoring features](https://assets.apitally.io/screenshots/overview.png)
monitoring-with-apitally/main.go (5)

14-18: Consider using exported fields for apiKeyInfo struct.

Since apiKeyInfo is used to populate the ApitallyConsumer struct (which has exported fields), consider making the fields in apiKeyInfo exported (capitalized) for consistency and to make the struct more reusable.

 type apiKeyInfo struct {
-	userID   string
-	userName string
-	group    string
+	UserID   string
+	UserName string
+	Group    string
 }

25-30: Hardcoded API keys in source code are a security risk.

Storing API keys directly in the source code, even with a comment indicating they would be in a database in production, presents a security risk. Consider using environment variables or a configuration file that's not checked into version control, even for example code.

 // API keys (in real life, these would be stored in a database)
 var apiKeys = map[string]apiKeyInfo{
-	"d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4": {userID: "user1", userName: "Alice", group: "admin"},
-	"8f4e2d1c9b7a5f3e2d8c6b4a9f7e3d1c": {userID: "user2", userName: "Bob", group: "developer"},
-	"3a9b8c7d6e5f4a2b1c9d8e7f6a5b4c3d": {userID: "user3", userName: "Charlie", group: "reader"},
+	"example-key-1": {userID: "user1", userName: "Alice", group: "admin"},
+	"example-key-2": {userID: "user2", userName: "Bob", group: "developer"},
+	"example-key-3": {userID: "user3", userName: "Charlie", group: "reader"},
 }

For a more robust approach, you could load these from environment variables:

// LoadAPIKeys loads API keys from environment variables
// Format: APIKEY_<key>=<userID>:<userName>:<group>
func LoadAPIKeys() map[string]apiKeyInfo {
    keys := make(map[string]apiKeyInfo)
    for _, env := range os.Environ() {
        if strings.HasPrefix(env, "APIKEY_") {
            parts := strings.SplitN(env, "=", 2)
            if len(parts) != 2 {
                continue
            }
            
            key := strings.TrimPrefix(parts[0], "APIKEY_")
            values := strings.Split(parts[1], ":")
            if len(values) != 3 {
                continue
            }
            
            keys[key] = apiKeyInfo{
                userID: values[0],
                userName: values[1],
                group: values[2],
            }
        }
    }
    return keys
}

80-87: GET endpoint returns static data.

The GET endpoint for books returns a static array rather than fetching from a database. This is appropriate for a simple example, but adding a comment to indicate this would help clarify that this is for demonstration purposes only.

 	// Routes
 	app.Get("/v1/books", func(c *fiber.Ctx) error {
+		// Return static data for demonstration purposes
 		books := []Book{
 			{Title: "The Go Programming Language", Author: "Alan A. A. Donovan"},
 			{Title: "Clean Code", Author: "Robert C. Martin"},
 		}
 		return c.JSON(books)
 	})

91-99: Request validation could be improved.

The endpoint validates the structure but doesn't have specific validation rules. Consider adding validation tags to the Book struct to demonstrate more comprehensive validation.

 type Book struct {
-	Title  string `json:"title"`
-	Author string `json:"author"`
+	Title  string `json:"title" validate:"required,min=1,max=100"`
+	Author string `json:"author" validate:"required,min=1,max=100"`
 }

106-108: Server startup lacks graceful shutdown.

The server starts correctly but doesn't implement graceful shutdown, which would be important for a production application. Consider adding an example of graceful shutdown handling.

 	// Start server
-	log.Fatal(app.Listen(":3000"))
+	// Setup graceful shutdown
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+
+	go func() {
+		<-c
+		fmt.Println("Gracefully shutting down...")
+		_ = app.Shutdown()
+	}()
+
+	// Start server
+	if err := app.Listen(":3000"); err != nil && err != http.ErrServerClosed {
+		log.Fatal(err)
+	}

This requires additional imports:

import (
    // existing imports...
    "fmt"
    "net/http"
    "os"
    "os/signal"
    "syscall"
)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ff4f2a and 8916f4d.

⛔ Files ignored due to path filters (2)
  • monitoring-with-apitally/go.mod is excluded by !**/*.mod
  • monitoring-with-apitally/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (2)
  • monitoring-with-apitally/README.md (1 hunks)
  • monitoring-with-apitally/main.go (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.21.2)
monitoring-with-apitally/README.md

48-48:

(curl-auth-header)

🔇 Additional comments (8)
monitoring-with-apitally/README.md (4)

1-5: Frontmatter looks good.

The YAML frontmatter correctly defines the title, keywords, and description for the recipe, which will help with searchability and organization within the recipes collection.


7-11: Introduction and repository links are well-structured.

The README properly introduces the recipe with badges linking to the GitHub repository and StackBlitz, making it easy for users to access the code. The concise description effectively communicates the purpose of the recipe.


30-37: API client ID setup instructions are clear.

The instructions for obtaining and configuring the Apitally client ID are straightforward and include a code snippet showing where to place it. This helps users get started quickly.


59-62: References section is helpful.

The references section provides useful links to both the Apitally and Fiber documentation, which is important for users who want to learn more about either technology.

monitoring-with-apitally/main.go (4)

3-12: Import organization is good.

The imports are well-organized, grouping standard library imports first, followed by third-party packages. The explicit import of the Apitally package with an alias improves readability.


20-23: Book struct definition looks good.

The Book struct is properly defined with JSON tags, which will ensure correct serialization when returned in API responses.


32-50: Good secure implementation of API key validation.

The API key validation function correctly uses crypto/sha256 for hashing and subtle.ConstantTimeCompare to prevent timing attacks. Setting consumer information for Apitally tracking is also well implemented.


73-78: API key authentication middleware is properly configured.

The keyauth middleware is correctly set up with proper key lookup path and authentication scheme. The validateAPIKey function is appropriately referenced as the validator.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
monitoring-with-apitally/main.go (1)

90-105: ⚠️ Potential issue

The POST endpoint implementation is incomplete.

The POST endpoint contains a placeholder comment but doesn't implement any actual storage logic. This issue was flagged in previous reviews but hasn't been addressed.

Add in-memory storage functionality to demonstrate the full request flow:

+// In-memory storage for books (for demonstration purposes only)
+var books = []Book{
+    {Title: "The Go Programming Language", Author: "Alan A. A. Donovan"},
+    {Title: "Clean Code", Author: "Robert C. Martin"},
+}

 app.Get("/v1/books", func(c *fiber.Ctx) error {
-		books := []Book{
-			{Title: "The Go Programming Language", Author: "Alan A. A. Donovan"},
-			{Title: "Clean Code", Author: "Robert C. Martin"},
-		}
 		return c.JSON(books)
 	})

 app.Post("/v1/books", func(c *fiber.Ctx) error {
 		// Parse and validate the request body
 		var req Book
 		if err := c.BodyParser(&req); err != nil {
 			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
 		}
 		if err := validate.Struct(req); err != nil {
 			// Capture validation errors in Apitally
 			apitally.CaptureValidationError(c, err)
 			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
 		}

-		// Logic to create a post goes here ...
+		// Add book to in-memory collection
+		books = append(books, req)

-		return c.Status(fiber.StatusCreated).Send(nil)
+		return c.Status(fiber.StatusCreated).JSON(req)
 	})
🧹 Nitpick comments (2)
monitoring-with-apitally/README.md (1)

41-41: Consider using a clear placeholder format for the API key in the example.

The curl example uses what appears to be a real API key format. Although this matches one of the test keys in your code, security scanners may flag this pattern, and users might mistakenly think this is a valid key.

Consider replacing it with a more obvious placeholder:

-    curl -X GET -H "Authorization: Bearer d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4" http://localhost:3000/v1/books
+    curl -X GET -H "Authorization: Bearer example-api-key-12345" http://localhost:3000/v1/books
🧰 Tools
🪛 Gitleaks (8.21.2)

41-41:

(curl-auth-header)

monitoring-with-apitally/main.go (1)

26-31: Consider adding validation for API keys

The API keys are hardcoded and stored in a map with no validation of their format or strength. In a real application, these would need to be securely stored and validated.

For a more complete example, consider adding a comment emphasizing this is only for demonstration:

-// API keys (in real life, these would be stored in a database)
+// API keys for demo purposes only
+// WARNING: In production applications:
+// 1. Never hardcode API keys in source code
+// 2. Use a secure database or key management system
+// 3. Implement key rotation and revocation capabilities
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8916f4d and 2994c5c.

📒 Files selected for processing (2)
  • monitoring-with-apitally/README.md (1 hunks)
  • monitoring-with-apitally/main.go (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.21.2)
monitoring-with-apitally/README.md

41-41:

(curl-auth-header)

🔇 Additional comments (2)
monitoring-with-apitally/main.go (2)

33-51: LGTM! Secure API key validation implementation.

The API key validation uses cryptographically secure methods:

  1. Uses SHA-256 hashing
  2. Employs constant-time comparison to prevent timing attacks
  3. Sets consumer information for Apitally tracking

57-72: LGTM! Good Apitally configuration with environment variable.

The Apitally middleware is properly configured using an environment variable for the client ID, addressing a previous review comment. The request logging configuration is comprehensive, capturing headers, bodies, and panic events.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
monitoring-with-apitally/README.md (5)

15-18: Specify minimum Go version.
It’s helpful to list the required Go version (e.g., Go 1.18+) under Prerequisites to prevent compatibility issues.


29-31: Use go mod tidy to install dependencies.
In a Go module, running go mod tidy (or go mod download) is preferred over go get to populate go.sum without unintentionally adding or upgrading dependencies. For example:

- go get
+ go mod tidy

32-33: Clarify Apitally client ID vs. API key.
The instructions ask to “Obtain a client ID” for Apitally, yet the API uses a Bearer token. It may help to note that the Apitally client ID is only for monitoring, and that users should generate or use their own API key/token for authenticating requests if required.


42-44: Avoid hardcoded dummy token in example.
Example bearer tokens can be flagged by credential scanners. Replace with a placeholder like <YOUR_API_TOKEN>:

- curl -X GET -H "Authorization: Bearer d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4" http://localhost:3000/v1/books
+ curl -X GET -H "Authorization: Bearer <YOUR_API_TOKEN>" http://localhost:3000/v1/books
🧰 Tools
🪛 Gitleaks (8.21.2)

43-43:

(curl-auth-header)


52-53: Enhance image accessibility.
Use a more descriptive alt text for the dashboard screenshot, for example:

![Apitally dashboard overview](https://assets.apitally.io/screenshots/overview.png)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1f9b15 and eb88b9f.

📒 Files selected for processing (1)
  • monitoring-with-apitally/README.md (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.21.2)
monitoring-with-apitally/README.md

43-43:

(curl-auth-header)

🔇 Additional comments (5)
monitoring-with-apitally/README.md (5)

1-5: YAML front matter looks correct.
The title, keywords, and description are properly defined and follow the project’s conventions.


23-25: Setup instructions are accurate.
The clone and cd commands correctly point to the monitoring-with-apitally directory.


36-39: Running instructions are clear.
Exporting APITALLY_CLIENT_ID and executing go run main.go will start the server as expected.


56-57: References are relevant.
Linking to the official Apitally and Fiber documentation will guide users seeking more in-depth information.


9-10:

✅ Verification successful

Verify the GitHub badge branch reference.
The badge URL uses tree/master; if this repository’s default branch is now main, the link will break. Please confirm the default branch and update the URL accordingly:


🏁 Script executed:

gh api repos/gofiber/recipes --jq .default_branch

Length of output: 58


Badge URL branch reference is correct

Verified that the repository’s default branch is master, so the existing badge links using tree/master are accurate and do not require update.

@ReneWerner87
Copy link
Member

ReneWerner87 commented May 14, 2025

THX for the example @itssimon

pls follow the https://github.com/gofiber/recipes/blob/master/.github/CONTRIBUTING.md and execute the make generate command at the end

@itssimon
Copy link
Contributor Author

Thanks @ReneWerner87. That's done now and the table of contents is updated!

@ReneWerner87 ReneWerner87 merged commit cc4cb31 into gofiber:master May 14, 2025
6 checks passed
@welcome
Copy link

welcome bot commented May 14, 2025

Congrats on merging your first pull request! 🎉 We here at Fiber are proud of you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants