Heim > Artikel > Backend-Entwicklung > Erstellen einer Blog-API mit Gin, FerretDB und oapi-codegen
In diesem Tutorial führen wir den Prozess der Erstellung einer RESTful-API für eine einfache Blog-Anwendung mit Go durch. Wir werden die folgenden Technologien verwenden:
Zuerst richten wir unser Go-Projekt ein und installieren die notwendigen Abhängigkeiten:
mkdir blog-api cd blog-api go mod init github.com/yourusername/blog-api go get github.com/gin-gonic/gin go get github.com/deepmap/oapi-codegen/cmd/oapi-codegen go get github.com/FerretDB/FerretDB
Erstellen Sie eine Datei mit dem Namen api.yaml in Ihrem Projektstamm und definieren Sie die OpenAPI 3.0-Spezifikation für unsere Blog-API:
openapi: 3.0.0 info: title: Blog API version: 1.0.0 paths: /posts: get: summary: List all posts responses: '200': description: Successful response content: application/json: schema: type: array items: $ref: '#/components/schemas/Post' post: summary: Create a new post requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/NewPost' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/Post' /posts/{id}: get: summary: Get a post by ID parameters: - name: id in: path required: true schema: type: string responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Post' put: summary: Update a post parameters: - name: id in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/NewPost' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/Post' delete: summary: Delete a post parameters: - name: id in: path required: true schema: type: string responses: '204': description: Successful response components: schemas: Post: type: object properties: id: type: string title: type: string content: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time NewPost: type: object required: - title - content properties: title: type: string content: type: string
Jetzt verwenden wir oapi-codegen, um den Servercode basierend auf unserer API-Spezifikation zu generieren:
oapi-codegen -package api api.yaml > api/api.go
Dieser Befehl erstellt ein neues Verzeichnis namens api und generiert die Datei api.go, die die Serverschnittstellen und -modelle enthält.
Erstellen Sie eine neue Datei mit dem Namen db/db.go, um die Datenbankschicht mit FerretDB zu implementieren:
package db import ( "context" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type Post struct { ID primitive.ObjectID `bson:"_id,omitempty"` Title string `bson:"title"` Content string `bson:"content"` CreatedAt time.Time `bson:"createdAt"` UpdatedAt time.Time `bson:"updatedAt"` } type DB struct { client *mongo.Client posts *mongo.Collection } func NewDB(uri string) (*DB, error) { client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(uri)) if err != nil { return nil, err } db := client.Database("blog") posts := db.Collection("posts") return &DB{ client: client, posts: posts, }, nil } func (db *DB) Close() error { return db.client.Disconnect(context.Background()) } func (db *DB) CreatePost(title, content string) (*Post, error) { post := &Post{ Title: title, Content: content, CreatedAt: time.Now(), UpdatedAt: time.Now(), } result, err := db.posts.InsertOne(context.Background(), post) if err != nil { return nil, err } post.ID = result.InsertedID.(primitive.ObjectID) return post, nil } func (db *DB) GetPost(id string) (*Post, error) { objectID, err := primitive.ObjectIDFromHex(id) if err != nil { return nil, err } var post Post err = db.posts.FindOne(context.Background(), bson.M{"_id": objectID}).Decode(&post) if err != nil { return nil, err } return &post, nil } func (db *DB) UpdatePost(id, title, content string) (*Post, error) { objectID, err := primitive.ObjectIDFromHex(id) if err != nil { return nil, err } update := bson.M{ "$set": bson.M{ "title": title, "content": content, "updatedAt": time.Now(), }, } var post Post err = db.posts.FindOneAndUpdate( context.Background(), bson.M{"_id": objectID}, update, options.FindOneAndUpdate().SetReturnDocument(options.After), ).Decode(&post) if err != nil { return nil, err } return &post, nil } func (db *DB) DeletePost(id string) error { objectID, err := primitive.ObjectIDFromHex(id) if err != nil { return err } _, err = db.posts.DeleteOne(context.Background(), bson.M{"_id": objectID}) return err } func (db *DB) ListPosts() ([]*Post, error) { cursor, err := db.posts.Find(context.Background(), bson.M{}) if err != nil { return nil, err } defer cursor.Close(context.Background()) var posts []*Post for cursor.Next(context.Background()) { var post Post if err := cursor.Decode(&post); err != nil { return nil, err } posts = append(posts, &post) } return posts, nil }
Erstellen Sie eine neue Datei mit dem Namen handlers/handlers.go, um die API-Handler zu implementieren:
package handlers import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/yourusername/blog-api/api" "github.com/yourusername/blog-api/db" ) type BlogAPI struct { db *db.DB } func NewBlogAPI(db *db.DB) *BlogAPI { return &BlogAPI{db: db} } func (b *BlogAPI) ListPosts(c *gin.Context) { posts, err := b.db.ListPosts() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } apiPosts := make([]api.Post, len(posts)) for i, post := range posts { apiPosts[i] = api.Post{ Id: post.ID.Hex(), Title: post.Title, Content: post.Content, CreatedAt: post.CreatedAt, UpdatedAt: post.UpdatedAt, } } c.JSON(http.StatusOK, apiPosts) } func (b *BlogAPI) CreatePost(c *gin.Context) { var newPost api.NewPost if err := c.ShouldBindJSON(&newPost); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } post, err := b.db.CreatePost(newPost.Title, newPost.Content) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, api.Post{ Id: post.ID.Hex(), Title: post.Title, Content: post.Content, CreatedAt: post.CreatedAt, UpdatedAt: post.UpdatedAt, }) } func (b *BlogAPI) GetPost(c *gin.Context) { id := c.Param("id") post, err := b.db.GetPost(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"}) return } c.JSON(http.StatusOK, api.Post{ Id: post.ID.Hex(), Title: post.Title, Content: post.Content, CreatedAt: post.CreatedAt, UpdatedAt: post.UpdatedAt, }) } func (b *BlogAPI) UpdatePost(c *gin.Context) { id := c.Param("id") var updatePost api.NewPost if err := c.ShouldBindJSON(&updatePost); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } post, err := b.db.UpdatePost(id, updatePost.Title, updatePost.Content) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"}) return } c.JSON(http.StatusOK, api.Post{ Id: post.ID.Hex(), Title: post.Title, Content: post.Content, CreatedAt: post.CreatedAt, UpdatedAt: post.UpdatedAt, }) } func (b *BlogAPI) DeletePost(c *gin.Context) { id := c.Param("id") err := b.db.DeletePost(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"}) return } c.Status(http.StatusNoContent) }
Erstellen Sie eine neue Datei mit dem Namen main.go im Projektstammverzeichnis, um die Anwendung einzurichten und auszuführen:
package main import ( "log" "github.com/gin-gonic/gin" "github.com/yourusername/blog-api/api" "github.com/yourusername/blog-api/db" "github.com/yourusername/blog-api/handlers" ) func main() { // Initialize the database connection database, err := db.NewDB("mongodb://localhost:27017") if err != nil { log.Fatalf("Failed to connect to the database: %v", err) } defer database.Close() // Create a new Gin router router := gin.Default() // Initialize the BlogAPI handlers blogAPI := handlers.NewBlogAPI(database) // Register the API routes api.RegisterHandlers(router, blogAPI) // Start the server log.Println("Starting server on :8080") if err := router.Run(":8080"); err != nil { log.Fatalf("Failed to start server: %v", err) } }
Da wir nun unsere API eingerichtet haben, testen wir sie mit Curl-Befehlen:
curl -X POST -H "Content-Type: application/json" -d '{"title":"My First Post","content":"This is the content of my first post."}' http://localhost:8080/posts
curl http://localhost:8080/posts
curl http://localhost:8080/posts/{id}
curl -X PUT -H "Content-Type: application/json" -d '{"title":"Updated Post","content":"This is the updated content."}' http://localhost:8080/posts/{id}
curl -X DELETE http://localhost:8080/posts/{id}
In diesem Tutorial haben wir eine einfache Blog-API mit dem Gin-Framework, FerretDB und oapi-codegen erstellt. Wir haben die folgenden Schritte behandelt:
Dieses Projekt zeigt, wie man mit Go eine RESTful-API erstellt und dabei die Leistungsfähigkeit der Codegenerierung und eine MongoDB-kompatible Datenbank nutzt. Sie können diese API weiter erweitern, indem Sie Authentifizierung, Paginierung und komplexere Abfragefunktionen hinzufügen.
Denken Sie daran, Fehler angemessen zu behandeln, eine ordnungsgemäße Protokollierung hinzuzufügen und Sicherheitsmaßnahmen zu implementieren, bevor Sie diese API in einer Produktionsumgebung bereitstellen.
Stehen Sie vor herausfordernden Problemen oder benötigen Sie eine externe Perspektive auf eine neue Idee oder ein neues Projekt? Ich kann helfen! Ganz gleich, ob Sie einen Technologie-Proof of Concept erstellen möchten, bevor Sie eine größere Investition tätigen, oder ob Sie Beratung bei schwierigen Themen benötigen, ich bin hier, um Ihnen zu helfen.
Wenn Sie an einer Zusammenarbeit mit mir interessiert sind, wenden Sie sich bitte per E-Mail an hungaikevin@gmail.com.
Lassen Sie uns Ihre Herausforderungen in Chancen verwandeln!
Das obige ist der detaillierte Inhalt vonErstellen einer Blog-API mit Gin, FerretDB und oapi-codegen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!