Maison > Article > développement back-end > Créer une API de blog avec Gin, FerretDB et oapi-codegen
Dans ce didacticiel, nous allons parcourir le processus de création d'une API RESTful pour une application de blog simple utilisant Go. Nous utiliserons les technologies suivantes :
Tout d'abord, configurons notre projet Go et installons les dépendances nécessaires :
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
Créez un fichier nommé api.yaml à la racine de votre projet et définissez la spécification OpenAPI 3.0 pour notre API de blog :
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
Maintenant, utilisons oapi-codegen pour générer le code du serveur basé sur notre spécification API :
oapi-codegen -package api api.yaml > api/api.go
Cette commande créera un nouveau répertoire appelé api et générera le fichier api.go contenant les interfaces et modèles du serveur.
Créez un nouveau fichier appelé db/db.go pour implémenter la couche de base de données à l'aide de FerretDB :
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 }
Créez un nouveau fichier appelé handlers/handlers.go pour implémenter les gestionnaires d'API :
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) }
Créez un nouveau fichier appelé main.go à la racine du projet pour configurer et exécuter l'application :
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) } }
Maintenant que notre API est opérationnelle, testons-la à l'aide des commandes curl :
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}
Dans ce tutoriel, nous avons construit une API de blog simple en utilisant le framework Gin, FerretDB et oapi-codegen. Nous avons couvert les étapes suivantes :
Ce projet montre comment créer une API RESTful avec Go, en tirant parti de la puissance de la génération de code et d'une base de données compatible MongoDB. Vous pouvez étendre davantage cette API en ajoutant des fonctionnalités d'authentification, de pagination et de requêtes plus complexes.
N'oubliez pas de gérer les erreurs de manière appropriée, d'ajouter une journalisation appropriée et de mettre en œuvre des mesures de sécurité avant de déployer cette API dans un environnement de production.
Êtes-vous confronté à des problèmes difficiles ou avez-vous besoin d'un point de vue externe sur une nouvelle idée ou un nouveau projet ? Je peux aider ! Que vous cherchiez à établir une preuve de concept technologique avant de réaliser un investissement plus important ou que vous ayez besoin de conseils sur des problèmes difficiles, je suis là pour vous aider.
Si vous souhaitez travailler avec moi, veuillez nous contacter par e-mail à hungaikevin@gmail.com.
Transformons vos défis en opportunités !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!