This guide walks through building a simple RESTful API in Go from scratch—no frameworks, just Go’s net/http package. It covers setting up routes, designing REST endpoints, handling requests, using an in-memory map for data storage, and ensuring thread safety with a mutex. Along the way, it highlights key REST principles, proper HTTP methods, and Go best practices for clean, concurrent web services. A must-read for developers learning Go backend fundamentals.This guide walks through building a simple RESTful API in Go from scratch—no frameworks, just Go’s net/http package. It covers setting up routes, designing REST endpoints, handling requests, using an in-memory map for data storage, and ensuring thread safety with a mutex. Along the way, it highlights key REST principles, proper HTTP methods, and Go best practices for clean, concurrent web services. A must-read for developers learning Go backend fundamentals.

Building a Simple REST API in Go Without Frameworks

2025/10/15 05:42

When I set out to build a web service in Go, I wanted to keep it simple.

After getting comfortable with Go’s basics, I challenged myself to create a simple RESTful API server from scratch. I decided not to use any frameworks — just Go’s standard net/http library — and to store data in memory rather than a database (just for simplicity to showcase it in this guide). Go is fast and efficient (it compiles to a single small binary and has strong concurrency support) . In this article, I’ll share what I learned about setting up routes, following RESTful principles, using an in-memory data store, and handling concurrency with a mutex.

What does “RESTful” actually mean?

Before coding, I made sure I understood the basics of RESTful API design. REST stands for Representational State Transfer, and it’s a style for designing networked applications. In a RESTful API, you treat server data as resources and use standard HTTP methods to operate on them. For example, you use GET to read data, POST to create data, PUT/PATCH to update, and DELETE to remove. Each resource is identified by a unique URL (often using nouns like /people or /people/123), and servers typically exchange data in a lightweight format like JSON . Another key principle is statelessness — each request from a client should contain all the information needed, so the server doesn’t keep track of client state between requests . These principles make APIs predictable and easy to use.

In practice, this meant designing clear endpoints and using the right HTTP methods. For my project, I chose to create a “person” resource as an example. The API would allow clients to create a new person, retrieve one or all persons, update a person’s info, or delete a person. Each operation corresponds to an HTTP method and endpoint:

  • POST /person — add a new person
  • GET /person?id=123 — get one person by ID (I used a query parameter for simplicity)
  • GET /persons — get all people
  • PUT /person?id=123 — update an existing person
  • DELETE /person?id=123 — delete a person

(In a fully RESTful design, you might use URLs like /person/123 instead of query parameters. But the idea is the same: the URL identifies the resource, and the HTTP verb tells the action.)

Importantly, each handler in my server checks the request method and returns an HTTP 405 “Method Not Allowed” if the method is wrong for that endpoint (for example, a GET request sent to the /person creation endpoint) . Using proper methods and status codes is part of being RESTful and helps avoid confusion.

Setting up Routing with Go’s

net/http

package

Go makes it straightforward to handle routes and requests using the net/http package. There’s a global HTTP request multiplexer (router) that you can use via http.HandleFunc, or you can create your own http.ServeMux. For this small project, I used the default and simply registered my endpoints with handler functions. Each handler is just a Go function with the signature func(w http.ResponseWriter, r *http.Request).

Here’s how I hooked up my routes in the main() function:

http.HandleFunc("/person", addPerson) http.HandleFunc("/person/get", getPerson) http.HandleFunc("/persons", getAllPersons) http.HandleFunc("/person/update", updatePerson) http.HandleFunc("/person/delete", deletePerson)  log.Println("Server running at http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) 

Each call to http.HandleFunc ties a URL path to a handler function. When a request comes in matching that path, Go’s HTTP server will invoke the corresponding function . In the code above, I set up five endpoints (as described earlier) and then start the server on port 8080. The http.ListenAndServe(“:8080”, nil) call begins listening for requests; it uses nil which means it will use the default mux where we registered our handlers. This call is blocking (it will run indefinitely until the program is stopped), and if the server fails to start, log.Fatal will print the error and exit.

A quick note on routing: The standard library’s router matches paths literally or with a simple prefix mechanism. In my case, I used distinct paths for each action (including /person/get, /person/update, etc.) to keep it simple. This isn’t the only way to design routes — one could use path parameters or a third-party router for more complex patterns — but it worked for this mini project.

Using an In-Memory Data Store (for now)

For storing data on the server, I chose to use an in-memory map rather than a database. This was purely for simplicity and learning purposes. I defined a struct type to represent a Person in our system:

\

type Person struct {   ID    int    `json:"id"`   Name  string `json:"name"`   Email string `json:"email"` } 

This struct has tags like json:”name” so that when we encode it to JSON, the fields come out in lowercase as expected by JSON clients. To hold the data, I declared a package-level variable db as a map from int to Person, and another variable idCounter to generate unique IDs for new records. For example:

var (   db        = make(map[int]Person)   idCounter = 1 ) 

This map db acts as a fake database. It’s a quick way to store data in memory and retrieve it by ID. The obvious downside is that the data won’t persist if the server restarts (and it’s not shared across multiple servers), but for a toy app or initial development, an in-memory store is extremely easy to work with. In fact, using a simple map let me avoid setup of a real database while learning the basics. Many beginner tutorials use this approach to simulate a database . It’s blazing fast and perfectly fine for small demos. (Of course, in a production application, you’d use a proper database like Postgres or MongoDB instead of a single server map!)

Handling Concurrency with a Mutex

One thing to be mindful of: as soon as you allow concurrent requests (and Go’s HTTP server does handle requests concurrently by default), you have to protect shared data. In our case, the db map and idCounter are shared between all requests. Without precautions, two clients creating people at the same time could try to update idCounter and the map concurrently, leading to a race condition or corrupted data.

Go’s solution is to use a sync.Mutex to lock critical sections. A mutex (mutual exclusion lock) ensures that only one goroutine can access the protected section at a time. I added a mu sync.Mutex variable alongside the db map. Then in each handler, I lock the mutex before reading or writing the map, and unlock it afterward. For example, in the addPerson handler, once I decode the request JSON into a Person struct, I do:

mu.Lock() p.ID = id Counterdb[p.ID] = p       // write to the map idCounter++ mu.Unlock() 

By locking around these operations, I ensure that no two requests can interleave these steps and cause inconsistent state. The same goes for reading: for instance, in a “get person” handler, I lock the mutex while retrieving from the map, then unlock once I have the result. This might seem unnecessary just for reading, but in Go even reads must be locked if there are any concurrent writes . The rule of thumb is: any shared variable that any goroutine might write to should be protected for all accesses (reads or writes). Go’s net/http server runs each request handler in its own goroutine, so without a lock, concurrent map access would eventually cause a crash or wrong behavior (the Go runtime will detect a concurrent map write and panic).

Using a mutex in this simple project taught me about thread safety in Go. It’s a low-level detail but crucial. The good news is that this locking overhead is negligible for a small number of requests, and it keeps our data safe. Again, for a real application, a database often handles concurrency internally, or one might use more advanced patterns (like concurrent maps or channels), but a basic mutex is straightforward and effective.

Implementing the CRUD Endpoints

With the groundwork done (routes, data store, and locking), I implemented the actual logic for each endpoint:

  • Create (POST /person): Read the JSON body of the request into a Person struct. Assign it a new ID (using idCounter), lock the mutex and save it in the map, then unlock. Finally, return the created person as JSON with a 201 Created status.
  • Read (GET /person?id=X): Check the id query parameter, convert it to an integer, then lock and retrieve the person from the map. If found, return it as JSON. If no such ID, return a 404 Not Found error.
  • Read All (GET /persons): Lock and loop through the map to collect all people into a slice, unlock, and return that slice as JSON.
  • Update (PUT /person?id=X): Parse the id from query params, decode JSON from request body for the updated data, then lock and check if the person exists. If not, return 404. If yes, update the record (keeping the same ID) in the map and unlock. Return the updated record as JSON.
  • Delete (DELETE /person?id=X): Parse the id, lock the map and delete the entry if it exists, then unlock. If no such person, return 404. If deletion was successful, return a simple confirmation message.

Each handler first validates that the HTTP method is correct (this is done by checking r.Method against the expected method). This way, if someone accidentally sends the wrong type of request (e.g., a GET to the create endpoint), we return an appropriate 405 error instead of trying to process it . Additionally, I set the Content-Type: application/json header on responses that contain JSON, so clients know how to parse the data.

I won’t list the full code for all handlers here, but the pattern is similar for each. The key takeaway is that Go’s simplicity shines here — reading JSON into a struct is one line (json.NewDecoder(r.Body).Decode(&p)), writing JSON out is one line (json.NewEncoder(w).Encode(data)), and error handling is straightforward with http.Error for sending error messages and status codes. The standard library gave me everything I needed to build a fully functional API.

Running and Testing the Server

To run the server, I simply execute the Go program (go run main.go or compile and run the binary). The server logs a message that it’s running on localhost:8080. I used curl and a tool like Postman to test each endpoint:

  • Create:
curl -X POST -H "Content-Type: application/json"\\      -d '{"name":"Alice","email":"[email protected]"}' \\      <http://localhost:8080/person> 
  • This should return a JSON with Alice’s data and an assigned id (e.g. {“id”:1,”name”:”Alice”,”email”:”[email protected]”}).
  • Get one:
curl "<http://localhost:8080/person/get?id=1>" 
  • This should return Alice’s data if the ID exists, or a 404 error if not.
  • Get all:
curl <http://localhost:8080/persons> 
  • Returns a list of all people in the map (in JSON array format).
  • Update:
curl -X PUT -H "Content-Type: application/json" \\      -d '{"name":"Alice Smith","email":"[email protected]"}' \\      <"http://localhost:8080/person/update?id=1"> 
  • This modifies Alice’s name/email and returns the updated JSON.
  • Delete:
curl -X DELETE "http://localhost:8080/person/delete?id=1" 
  • This deletes the person with ID 1, returning a confirmation message or 404 if not found.

I was able to verify that each endpoint behaved as expected. For instance, trying to fetch a non-existent ID returned my custom “Person not found” message with a 404 status, and the server correctly handled concurrent requests without issues (thanks to the mutex).

Best Practices I’m Learning

Through this project, I picked up some best practices for Go web services:

  1. Use the right HTTP method and status codes — Designing around REST principles makes your API intuitive. GET for reads, POST for creates, etc., and respond with proper HTTP status codes (200 OK, 201 Created, 404 Not Found, 405 Method Not Allowed, etc.) so clients know what happened. Following HTTP conventions is a big part of building a clean API .
  2. Keep handlers simple and focused — Each handler should do one thing (create, fetch, update, or delete). This separation makes the code easier to test and maintain. For example, my addPerson function doesn’t need to know anything about how the other handlers work — it just handles creation.
  3. Guard shared data with locks (or other sync tools) — Go’s concurrency is powerful, but you must avoid data races. Any state that persists beyond a single request (like the in-memory map in this server) needs protection . In our case a sync.Mutex was the easiest solution. It might feel low-level, but it prevents subtle bugs.
  4. Use the standard library to its fullest — It’s impressive how much you can do without any external packages. JSON encoding/decoding, HTTP routing, and even basic data storage (maps) are all built-in. This project was a great way to understand those before potentially moving to frameworks. As a beginner, it’s tempting to grab a big library, but I found a lot of value in first learning how things work under the hood.

Lessons from the “Mini REST” project

Working on this mini REST server solidified a few concepts for me:

  • Go makes concurrency easy… but you’re responsible for protecting data. The fact that net/http spins up a goroutine per request means high throughput out of the box, but also means you must handle synchronization for any shared state . I won’t forget to consider thread safety in future projects.
  • RESTful design isn’t too hard once you grasp it. It’s basically about resources and standard operations. Planning the endpoints first (with proper methods and paths) helped guide my implementation. It also made the API predictable to use. This exercise reinforced why following REST conventions is beneficial .
  • Starting simple is okay. Using an in-memory map and dummy data is fine for a learning project. It kept me focused on the core — handling HTTP requests — without the complexity of database setup. I understand that for real applications I’ll swap the map for a database and perhaps use a router framework for more features. But now I have a clear picture of what those tools are abstracting. As one resource put it, this kind of in-memory setup is fine for demos, but real projects should use a proper DB once you move beyond the toy stage .
  • Go’s standard library is powerful. I was able to go from nothing to a working web API without installing anything else. This project gave me confidence that I can implement web services in Go and that I understand the basics of how things work under the hood. Frameworks and libraries can still help (for routing, validation, etc.), but it’s great to know the fundamentals.

Building a simple RESTful API in Go has been a rewarding step in my journey as a Go developer. Not only do I have a small web service running, but I also gained practical experience with REST principles, the net/http package, and concurrency control. Going forward, I plan to explore more — maybe connecting this service to a real database, adding user authentication, or writing tests for my handlers. But as a starting point, this mini project has shown me that building a web API in Go is very achievable, even for a beginner. I’ll continue sharing what I learn as I delve deeper into Go for backend development!

Sources:

  1. DIY Golang Web Server: No Dependencies Needed! by Flo Woelki
  2. net/http Go documentation

\

Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact [email protected] for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.

You May Also Like

Ripple Buyers Step In at $2.00 Floor on BTC’s Hover Above $91K

Ripple Buyers Step In at $2.00 Floor on BTC’s Hover Above $91K

The post Ripple Buyers Step In at $2.00 Floor on BTC’s Hover Above $91K appeared on BitcoinEthereumNews.com. Token breaks above key support while volume surges 251% during psychological level defense at $2.00. News Background U.S. spot XRP ETFs continue pulling in uninterrupted inflows, with cumulative demand now exceeding $1 billion since launch — the fastest early adoption pace for any altcoin ETF. Institutional participation remains strong even as retail sentiment remains muted, contributing to market conditions where large players accumulate during weakness while short-term traders hesitate to re-enter. XRP’s macro environment remains dominated by capital rotation into regulated products, with ETF demand offsetting declining open interest in derivatives markets. Technical Analysis The defining moment of the session came during the $2.03 → $2.00 flush when volume spiked to 129.7M — 251% above the 24-hour average. This confirmed heavy selling pressure but, more importantly, marked the exact moment where institutional buyers absorbed liquidity at the psychological floor. The V-shaped rebound from $2.00 back into the $2.07–$2.08 range validates active demand at this level. XRP continues to form a series of higher lows on intraday charts, signaling early trend reacceleration. However, failure to break through the $2.08–$2.11 resistance cluster shows lingering supply overhead as the market awaits a decisive catalyst. Momentum indicators show bullish divergence forming, but volume needs to expand during upside moves rather than only during downside flushes to confirm a sustainable breakout. Price Action Summary XRP traded between $2.00 and $2.08 across the 24-hour window, with a sharp selloff testing the psychological floor before immediate absorption. Three intraday advances toward $2.08 failed to clear resistance, keeping price capped despite improving structure. Consolidation near $2.06–$2.08 into the session close signals stabilization above support, though broader range compression persists. What Traders Should Know The $2.00 level remains the most important line in the sand — both technically and psychologically. Institutional accumulation beneath this threshold hints at larger players…
Share
BitcoinEthereumNews2025/12/08 13:22
SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips

SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips

Ever wondered which meme coins could offer the next big breakout in 2025? With altcoins like SPX6900 and Official Trump trending in community chatter, the market is buzzing with potential, yet only a few offer genuine early-stage investment opportunities. Investors who missed previous moonshots are looking for projects that combine novelty, strong community, and robust presale mechanics. Among these, MOBU crypto has emerged as a strong contender for the next 100x crypto presale, thanks to its structured presale mechanics, active community engagement, and impressive early-stage ROI. MOBU Crypto: Next 100x Crypto Presale in Motion MOBU crypto stands out as the next 100x crypto presale with its meticulously structured presale offering and unique investment potential. Stage 6 is live at $0.00008388, boasting over 2,100 token holders and a presale tally surpassing $650K. Joining the presale is simple: connect the official website, choose your currency, and lock in before prices rise again. SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips 10 Moreover, the 95% APY Staking program gives holders consistent passive returns while maintaining flexibility. Tokens can be staked anytime through the dashboard, with rewards calculated daily and only a two-month lock-in on earnings. With $14.6 billion $MOBU allocated, this system rewards loyalty, encourages long-term participation, and strengthens liquidity, ensuring that all holders, small or large, share in the project’s growth and success. MOBU Crypto Precision Entry: Presale Power Boost The $MOBU presale is designed to maximize early investor rewards through first-come, first-served access. Investors can capitalize on scenarios such as a $200 purchase turning into $14,687.65 or a $300 investment that could reach $22,031.47. The presale mechanics encourage active participation while fostering community growth. SPX6900 (SPX) Shows Strong Weekly Momentum as Investor Interest Rises SPX6900 (SPX) recorded a notable upswing over the past week, reflecting renewed investor interest and increased participation across the meme coin sector. The asset’s recent upward movement showcases improving market sentiment and highlights the growing attention SPX6900 continues to attract within the crypto community. Market performance for SPX6900 also shows substantial activity, with its market capitalization and 24-hour trading volume remaining robust. The project’s fully diluted valuation similarly reflects strong potential should all tokens enter circulation, signaling steady confidence from traders and long-term holders. Official Trump (TRUMP) Faces Weekly Pullback as Market Correction Unfolds Official Trump (Official Trump) experienced a noticeable decline in its weekly performance as market-wide corrections and short-term investor profit-taking contributed to downward pressure. Despite the pullback, the asset continues to remain active within trading circles, supported by consistent engagement from its community. The cryptocurrency maintains substantial market capitalization and daily trading volume, illustrating steady market participation even during corrective phases. Its fully diluted valuation also highlights the long-term potential of the project if all tokens were to circulate, demonstrating ongoing interest from speculators and long-term market observers. SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips 11 Final Words SPX6900 and Official Trump continue to capture attention through meme-driven community engagement and trending collaborations. Their ongoing growth reflects broader market enthusiasm, yet they lack structured presale benefits like those offered by MOBU crypto. MOBU crypto, with Stage 6 live and over 2,100 token holders, provides a unique opportunity for investors seeking the next 100x crypto presale.  The presale provides first-come, first-served advantages, verified token allocations, and significant ROI potential, making it a must-watch project in the evolving meme coin landscape. SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips 12 For More Information: Website: Visit the Official MOBU Website  Telegram: Join the MOBU Telegram Channel Twitter: Follow MOBU ON X (Formerly Twitter) Frequently Asked Questions About the Next 100x Crypto Presale What is the 1000x meme coin in 2025? MOBU crypto is considered a strong candidate for high ROI potential, aiming for significant growth in 2025. Which coin is best to invest for 2025? The MOBU crypto presale is currently the next 100x crypto presale, thanks to its early-stage investment benefits. What meme coin has 1000x? Early investors in MOBU crypto presale have the potential for exponential gains as the project progresses to listing. What is the projected ROI for early MOBU crypto investors? Early investors until Stage 6 have achieved a 235.52% ROI with further price surge expected. Are MOBU crypto presale tokens safe? Yes, MOBU crypto tokens are distributed transparently, with audited processes that ensure security. Glossary of Key Terms Meme Coin: A cryptocurrency inspired by internet memes and pop culture.  Presale: An early-stage token sale offering initial access to investors.  ROI: Return on Investment; profit earned from an investment.  Token Holder: An individual or entity owning tokens of a cryptocurrency.  Listing Price: The price at which a cryptocurrency becomes available on exchanges.  First Come, First Served: Allocation strategy prioritizing early participants.  NFT: Non-Fungible Token; a unique digital asset often associated with meme projects. Summary MOBU crypto, SPX6900, and Official Trump offer diverse opportunities in the meme coin space, but MOBU crypto presale Stage 6 presents unmatched early-stage investment potential. With over 2,100 token holders, presale tally exceeding $640K, and ROI already surpassing 235%, MOBU crypto emerges as the next 100x crypto presale. The presale’s first-come, first-served approach creates FOMO-driven urgency, while a transparent token distribution ensures trust and accessibility. Disclaimer This article is for informational purposes only and does not constitute financial advice. Investors should conduct their own research before participating in any cryptocurrency presale or investment. Read More: SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips">SPX6900 Hits the Brakes, While MOBU Hits the Afterburners with its Next 100x Crypto presale, and TRUMP Dips
Share
Coinstats2025/12/08 11:45