-2

Below is the model for my code.

package models

type Goal struct {
  Id        int    `json:"id"`
  Title     string `json:"title"`
  Status        bool   `json:"status"`
}

When I import models package in controllers and want to use so it give me an errror.

package controllers

import (
    "strconv"
    "github.com/gofiber/fiber/v2"
    "github.com/RohitKuwar/go_fiber/models"  //error:"github.com/RohitKuwar/go_fiber/models" imported but not used
)

var goals = []Goal{     //error:undeclared name: Goal
    {
        Id:        1,
        Title:     "Read about Promises",
        Status:    "completed",
    },
    {
        Id:        2,
        Title:     "Read about Closures",
        Status:    "active",
    },
}

func GetGoals(c *fiber.Ctx) error {
    return c.Status(fiber.StatusOK).JSON(goals)
}

func CreateGoal(c *fiber.Ctx) error {
    type Request struct {
        Title   string  `json:"title"`
        Status  string  `json:"status"`
    }

    var body Request

    err := c.BodyParser(&body)

    // if error
    if err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
            "message": "Cannot parse JSON",
            "error":   err,
        })
    }

    // create a goal variable
    goal := &Goal{     //error:undeclared name: Goal
        Id:        len(goals) + 1,
        Title:     body.Title,
        Status:      body.Status,
    }

But when I write models in the controller like below then everything works fine.

import (
    "strconv"
    "github.com/gofiber/fiber/v2"
)

type Goal struct {
  Id        int    `json:"id"`
  Title     string `json:"title"`
  Status    string  `json:"status"`
}

var goals = []Goal{
    {
        Id:        1,
        Title:     "Read about Promises",
        Status:    "completed",
    },
    {
        Id:        2,
        Title:     "Read about Closures",
        Status:    "active",
    },
}
func GetGoals(c *fiber.Ctx) error {
    return c.Status(fiber.StatusOK).JSON(goals)
}

But I do not want to use models code in controllers code. I want to keep the model in the models folder. I want to keep models and controllers in separate folders. I think I am doing something wrong while importing models package in controllers or controllers package in models. I am not understanding how can I do it. Can you guys please help me? Thank you in advance.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • See https://stackoverflow.com/q/25924749/13860 – Jonathan Hall Aug 19 '21 at 07:47
  • 1
    "I want to keep the model in the models folder. I want to keep models and controllers in separate folders." Yes you want this. But your want is wrong. Put related things into a single package. – Volker Aug 19 '21 at 07:55
  • 1
    You need to [qualify imported names](https://golang.org/ref/spec#Qualified_identifiers) with the name of the package in which they were declared. Just like you're doing with `Ctx` from `fiber` (i.e. `fiber.Ctx`), the same goes for any other imported name, doesn't matter if it's stdlib package, 3rd party package, or a package local to your project. – mkopriva Aug 19 '21 at 07:57
  • Note that most consider MVC a poor design choice for Go programs. (In my opinion, it's a poor design choice everywhere else, too) – Jonathan Hall Aug 19 '21 at 08:04
  • @Filmzy Then which design will you suggest? Is there any standard way or practice? –  Aug 19 '21 at 08:10

1 Answers1

0

How does your go.mod file looks like? I tried to work your code with the following directory structure with the module entry in go.mod looking like module rishabh96b/go_fiber

➜  go_fiber tree .
.
├── controllers
│   └── mycontroller.go
├── go.mod
├── go.sum
└── models
    └── goals.go

Importing models package in controller is successful in my case. Here is how mycontroller.go file looks like

package controllers

import (
    . "rishabh96b/go_fiber/models"

    "github.com/gofiber/fiber/v2"
)

var goals = []Goal{ //error:undeclared name: Goal
    {
        Id:     1,
        Title:  "Read about Promises",
        Status: "completed",
    },
    {
    Id:     2,
    Title:  "Read about Closures",
    Status: "active",
    },
}

func GetGoals(c *fiber.Ctx) error {
    return c.Status(fiber.StatusOK).JSON(goals)
}

func CreateGoal(c *fiber.Ctx) error {
    type Request struct {
        Title  string `json:"title"`
        Status string `json:"status"`
    }

var body Request

err := c.BodyParser(&body)

// if error
if err != nil {
    return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
        "message": "Cannot parse JSON",
        "error":   err,
    })
}

// create a goal variable
goal := &Goal{ //error:undeclared name: Goal
    Id:     len(goals) + 1,
    Title:  body.Title,
    Status: body.Status,
    }
}

P.S: The . in front of "rishabh96b/go_fiber/models" means that I don't have to use package name with struct I am using here. In short, I can simply use Goal{} instead of models.Goal{}

borz
  • 313
  • 4
  • 10
  • My directory structure is the same as yours. By putting `dot(.)` in front of the model package things are working for me now. Thanks for the help. But the problem is that VS Code is showing an underlined error below that model package name and the error is `should not use dot imports`. Can you please help me with this? –  Aug 19 '21 at 08:38
  • It is fine to use `dot(.)` notation but it should have a specific purpose. My VSCode uses `staticcheck` linter and does not throw an error on this. You can check if you have some other linter like `golint`, `golangci-lint` etc. which is throwing this out. `Settings -> Extensions -> Go - Lint Tools>` – borz Aug 19 '21 at 09:42
  • Also consider marking answer as accepted if it solves the original problem. Thanks! – borz Aug 19 '21 at 09:43