how to receive json array in golang with echo - vuejs2

in vue I have the following structure let dat = [
{
name: "johan",
"Age": "21"
},
{
name: "camilo",
Age: "22"
}
]
I would like to know how to receive this data in go with echo

You can use the Bind function on the handlers echo.Context to unmarshal the data into a matching structure.
Example below:
package main
import (
"log"
"net/http"
"github.com/labstack/echo"
)
func main() {
// setup echo
e := echo.New()
e.POST("/people", PeopleHandler())
// start webserver
http.Handle("/", e)
log.Fatal(http.ListenAndServe(":8080", nil))
}
// PeopleHandler endpoint handler
func PeopleHandler() echo.HandlerFunc {
return func(c echo.Context) error {
p := &[]Person{}
if err := c.Bind(p); err != nil { // here unmarshal request body into p
return c.String(http.StatusInternalServerError, err.Error())
}
return c.JSON(http.StatusOK, p)
}
}
// Person represents an individual.
type Person struct {
Name string `json:"name"`
Age string `json:"age"`
}
Test via curl:
curl --header "Content-Type: application/json" \
--request POST \
--data '[{"name":"johan","Age":"21"},{"name": "camilo","Age": "22"}]' \
http://localhost:8080/people

Related

How to correctly use the AnonFiles API to post files?

I am trying to make a function where it hosts your file on the anonfiles.com website using the anonfiles API. Even thought I am correctly using the api, it always returns nil. Response is missing message.
func host(file string) {
fileBytes, err := ioutil.ReadFile(file)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not read file,", err, "\033[0m")
return
}
url := "https://api.anonfiles.com/upload"
request, err := http.NewRequest("POST", url, bytes.NewBuffer(fileBytes))
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not post request,", err, "\033[0m")
return
}
request.Header.Set("Content-Type", "application/octet-stream")
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not send request,", err, "\033[0m")
return
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not read response,", err, "\033[0m")
return
}
var result map[string]interface{}
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not parse response,", err, "\033[0m")
return
}
if response.StatusCode == 200 {
if result["url"] == nil {
fmt.Println("\033[1;31mCommand > Host: Response is missing URL\033[0m")
return
}
fmt.Println("File hosted successfully:", result["url"].(string))
} else {
if result["message"] == nil {
fmt.Println("\033[1;31mCommand > Host: Response is missing message\033[0m")
return
}
fmt.Println("\033[1;31mCommand > Host:\033[0m", result["message"].(string))
}
}
I'd thought I'd take a moment to expand those comments into an answer.
First, as we we've already discussed, you're not using the correct API to upload files. If we modify your code to show the complete response body, like this:
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not send request,", err, "\033[0m")
return
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("\033[1;31mCommand > Host: Could not read response,", err, "\033[0m")
return
}
fmt.Printf("BODY:\n%s\n", body)
We see the following:
{
"status": false,
"error": {
"message": "No file chosen.",
"type": "ERROR_FILE_NOT_PROVIDED",
"code": 10
}
}
We're getting this error because you're not providing the file parameter in a multipart/form-data request. The post to which I linked earlier has several examples of sending a multipart request; I've tested a couple of them and they seem to work as expected.
You're also making incorrect assumptions about the response returned by the API. If we make a successful request using curl and capture the response JSON, we find that it looks like this:
{
"status": true,
"data": {
"file": {
"url": {
"full": "https://anonfiles.com/k8cdobWey7/test_txt",
"short": "https://anonfiles.com/k8cdobWey7"
},
"metadata": {
"id": "k8cdobWey7",
"name": "test.txt",
"size": {
"bytes": 12,
"readable": "12 B"
}
}
}
}
}
Note that there is no response["url"] or response["message"]. If you want the URL for the uploaded file, you need to get response["data"]["file"]["url"]["full"] (or ["short"]).
Similarly, we can see examples of the error response above, which looks like this:
{
"status": false,
"error": {
"message": "No file chosen.",
"type": "ERROR_FILE_NOT_PROVIDED",
"code": 10
}
}
That's not result["message"]; that's result["error"]["message"].
Because you're unmarshalling into a map[string]interface, getting at these nested keys is going to be a bit of a pain. I found it easiest to create Go structs for the above responses, and just unmarshal into an appropriately typed variable.
That gets me the following types:
type (
AnonFilesUrl struct {
Full string `json:"full"`
Short string `json:"short"`
}
AnonFilesMetadata struct {
ID string `json:"id"`
Name string `json:"name"`
Size struct {
Bytes int `json:"bytes"`
Readable string `json:"readable"`
} `json:"size"`
}
AnonFilesData struct {
File struct {
URL AnonFilesUrl `json:"url"`
Metadata AnonFilesMetadata `json:"metadata"`
} `json:"file"`
}
AnonFilesError struct {
Message string
Type string
Code int
}
AnonFilesResponse struct {
Status bool `json:"status"`
Data AnonFilesData `json:"data"`
Error AnonFilesError `json:"error"`
}
)
And then unmarshalling the response looks like:
var result AnonFilesResponse
err = json.Unmarshal(body, &result)
And we can ask for fields like:
fmt.Printf("URL: %s\n", result.Data.File.URL.Full)

multiple response in single array in golang

I am new to golang . and I want to get my response as multiple result. I do some method but I need to change that one
impartErrl := ph.profileService.ValidateSchema(gojsonschema.NewStringLoader(string(b)))
if impartErrl != nil {
ctx.JSON(http.StatusBadRequest, impart.ErrorResponse(impartErrl))
return
}
func (ps *profileService) ValidateSchema(document gojsonschema.JSONLoader) (errors []impart.Error) {
result, err := gojsonschema.Validate(ps.schemaValidator, document)
if err != nil {
ps.SugaredLogger.Error(err.Error())
return impart.ErrorResponse(
impart.NewError(impart.ErrBadRequest, "unable to validate schema"),
)
}
if result.Valid() {
return nil
}
// msg := fmt.Sprintf("%v validations errors.\n", len(result.Errors()))
msg := "validations errors"
for i, desc := range result.Errors() {
msg += fmt.Sprintf("%v: %s\n", i, desc)
er := impart.NewError(impart.ErrValidationError, fmt.Sprintf("%s ", desc), impart.ErrorKey(desc.Field()))
errors = append(errors, er)
}
return errors
}
func NewError(err error, msg string, args ...interface{}) Error {
key := GetErrorKey(args...)
return impartError{
err: err,
msg: msg,
key: key,
}
}
func ErrorResponse(err interface{}) []Error {
var errorResponse []Error
switch err.(type) {
case Error:
errorResponse = []Error{err.(Error)}
case []Error:
errorResponse = err.([]Error)
default:
errorResponse = []Error{
NewError(ErrUnknown, fmt.Sprintf("%v", err)),
}
}
return errorResponse
}
type Error interface {
error
HttpStatus() int
ToJson() string
Err() error
Msg() string
}
Now I am getting the output as
[
{
"error": "validation error",
"msg": "email: Does not match format 'email' ",
"key": "email"
},
{
"error": "validation error",
"msg": "screenName: String length must be greater than or equal to 4 ",
"key": "screenName"
}
]
but I require my response as
{
0 :{
"error": "validation error",
"msg": "email: Does not match format 'email' ",
"key": "email"
},
1 : {
"error": "unable to complete the request",
"msg": "invalid screen name, must be alphanumeric characters only",
"key": "screen_name"
}
}
How can I get these type of response. ? because in ios app while parsing the response [] showing error. so I need to change the output.
please help me.
The ErrorResponse func should return a map[int]Error instead of []Error. As Example:
func ErrorResponse(err interface{}) map[int]Error {
errorResponse := map[int]Error{}
switch e := err.(type) {
case Error:
errorResponse[0] = e
case []Error:
for i, k := range e {
errorResponse[i] = k
}
default:
errorResponse[0] = NewError(ErrUnknown, fmt.Sprintf("%v", err))
}
return errorResponse
}

How can I make struct in go for object having array of object inside it?

I am using Vuejs on the frontend and Go language on the backend. My data variable has data in the following format.
var data = {
software_type: this.$props.selected,
selected_solutions: this.fromChildChecked,
};
By doing console.log(data)in frontend, I get following output.
On the backend side, I have struct on this format :
type Technology struct {
ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
SoftwareType string `json:"software_type" bson:"software_type"`
SelectedSolutions struct {
selectedSolutions []string
} `json:"selected_solutions" bson:"selected_solutions"`
}
I am quite sure about the problem that I am having and it might be due to the difference with the format of data that I am sending and the struct that I have made.
I am using MongoDB as a database.
By submitting the form, data comes to DB in the following format, which means, I am getting an empty object for selected_solutions.
{
"_id":{"$oid":"5f5a1fa8885112e153b5a890"},
"software_type":"Cross-channel Campain Mangment Software",
"selected_solutions":{}
}
This is the format that I expect to be on DB or something similar to below.
{
"_id":{"$oid":"5f5a1fa8885112e153b5a890"},
"software_type":"Cross-channel Campain Mangment Software",
"selected_solutions":{
Adobe Campaign: ["Business to Customer (B2C)", "Business to Business (B2B)"],
Marin Software: ["E-Government", "M-Commerce"],
}
}
How can I change struct to make it compatible with the data that I am trying to send? Thank you in advance for any help.
EDIT: This is how I am submitting data.
postUserDetails() {
var data = {
software_type: this.$props.selected,
selected_solutions: this.fromChildChecked,
};
console.log(data);
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: JSON.stringify(data),
};
fetch("http://localhost:8080/technology", requestOptions)
.then((response) => {
response.json().then((data) => {
if (data.result === "success") {
//this.response_message = "Registration Successfull";
console.log("data posted successfully");
} else if (data.result === "er") {
// this.response_message = "Reagestraion failed please try again";
console.log("failed to post data");
}
});
})
.catch((error) => {
console.error("error is", error);
});
},
mounted() {
this.postUserDetails();
},
This is the function for backend controller.
//TechnologyHandler handles checkbox selection for technology section
func TechnologyHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/json")
w.Header().Add("Access-Control-Allow-Credentials", "true")
var technologyChoices model.Technology
//var selectedSolution model.Selected
//reads request body and and stores it inside body
body, _ := ioutil.ReadAll(r.Body)
//body is a json object, to convert it into go variable json.Unmarshal()is used ,
//which converts json object to User object of go.
err := json.Unmarshal(body, &technologyChoices)
var res model.TechnologyResponseResult
if err != nil {
res.Error = err.Error()
json.NewEncoder(w).Encode(res)
return
}
collection, err := db.TechnologyDBCollection()
if err != nil {
res.Error = err.Error()
json.NewEncoder(w).Encode(res)
return
}
_, err = collection.InsertOne(context.TODO(), technologyChoices)
if err != nil {
res.Error = "Error While Creating Technology choices, Try Again"
res.Result = "er"
json.NewEncoder(w).Encode(res)
return
}
res.Result = "success"
json.NewEncoder(w).Encode(res)
return
}
Based on your database structure, selected_solutions is an object containing string arrays:
type Technology struct {
ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
SoftwareType string `json:"software_type" bson:"software_type"`
SelectedSolutions map[string][]string `json:"selected_solutions" bson:"selected_solutions"`
}

How to write a response for kubernetes admission controller

I am trying to write a simple admission controller for pod naming (validation) but for some reason I am generating a wrong response.
Here is my code:
package main
import (
"fmt"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/golang/glog"
// for Kubernetes
"k8s.io/api/admission/v1beta1"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"regexp"
)
type myValidServerhandler struct {
}
// this is the handler fuction from the HTTP server
func (gs *myValidServerhandler) serve(w http.ResponseWriter, r *http.Request) {
var Body []byte
if r.Body != nil {
if data , err := ioutil.ReadAll(r.Body); err == nil {
Body = data
}
}
if len(Body) == 0 {
glog.Error("Unable to retrive Body from API")
http.Error(w,"Empty Body", http.StatusBadRequest)
return
}
glog.Info("Received Request")
// this is where I make sure the request is for the validation prefix
if r.URL.Path != "/validate" {
glog.Error("Not a Validataion String")
http.Error(w,"Not a Validataion String", http.StatusBadRequest)
return
}
// in this part the function takes the AdmissionReivew and make sure in is in the right
// JSON format
arRequest := &v1beta1.AdmissionReview{}
if err := json.Unmarshal(Body, arRequest); err != nil {
glog.Error("incorrect Body")
http.Error(w, "incorrect Body", http.StatusBadRequest)
return
}
raw := arRequest.Request.Object.Raw
pod := v1.Pod{}
if err := json.Unmarshal(raw, &pod); err != nil {
glog.Error("Error Deserializing Pod")
return
}
// this is where I make sure the pod name contains the kuku string
podnamingReg := regexp.MustCompile(`kuku`)
if podnamingReg.MatchString(string(pod.Name)) {
return
} else {
glog.Error("the pod does not contain \"kuku\"")
http.Error(w, "the pod does not contain \"kuku\"", http.StatusBadRequest)
return
}
// I think the main problem is with this part of the code because the
// error from the events I getting in the Kubernetes namespace is that
// I am sending 200 without a body response
arResponse := v1beta1.AdmissionReview{
Response: &v1beta1.AdmissionResponse{
Result: &metav1.Status{},
Allowed: true,
},
}
// generating the JSON response after the validation
resp, err := json.Marshal(arResponse)
if err != nil {
glog.Error("Can't encode response:", err)
http.Error(w, fmt.Sprintf("couldn't encode response: %v", err), http.StatusInternalServerError)
}
glog.Infof("Ready to write response ...")
if _, err := w.Write(resp); err != nil {
glog.Error("Can't write response", err)
http.Error(w, fmt.Sprintf("cloud not write response: %v", err), http.StatusInternalServerError)
}
}
The code is working as expected except for a positive output (where the pod name meets the criteria)
there is another file with a main just grabbing the TLS files and starting the HTTP service.
so after a few digging I found what was wrong with my code
first this part
if podnamingReg.MatchString(string(pod.Name)) {
return
} else {
glog.Error("the pod does not contain \"kuku\"")
http.Error(w, "the pod does not contain \"kuku\"", http.StatusBadRequest)
return
}
by writing "return" twice I discarded the rest of the code and more so I haven't attached the request UID to the response UID and because I am using the v1 and not the v1beta1 I needed to adding the APIVersion in the response
so the rest of the code looks like :
arResponse := v1beta1.AdmissionReview{
Response: &v1beta1.AdmissionResponse{
Result: &metav1.Status{},
Allowed: false,
},
}
podnamingReg := regexp.MustCompile(`kuku`)
if podnamingReg.MatchString(string(pod.Name)) {
fmt.Printf("the pod %s is up to the name standard", pod.Name)
arResponse.Response.Allowed = true
}
arResponse.APIVersion = "admission.k8s.io/v1"
arResponse.Kind = arRequest.Kind
arResponse.Response.UID = arRequest.Request.UID
so I needed to add the 2 parts and make sure that in case the pod name is not up to standard then I need to return the right response

Send application/x-www-form-urlencoded in Ktor

I can't figure out how to send a application/x-www-form-urlencoded POST request in Ktor. I see some submitForm helpers in Ktor's documentation but they don't send the request as expected.
What I want is to replicate this curl line behavior:
curl -d "param1=lorem&param2=ipsum" \
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
https://webservice/endpoint
My dependency is on io.ktor:ktor-client-cio:1.0.0.
After several tries I managed to send the request with the following code:
val url = "https://webservice/endpoint"
val client = HttpClient()
return client.post(url) {
body = FormDataContent(Parameters.build {
append("param1", "lorem")
append("param2", "ipsum")
})
}
val response: HttpResponse = client.submitForm(
url = "http://localhost:8080/get",
formParameters = Parameters.build {
append("first_name", "Jet")
append("last_name", "Brains")
},
encodeInQuery = true
)
https://ktor.io/docs/request.html#form_parameters
Looking for information I found the way to do it
suspend inline fun <reified T> post(path: String, requestBody: FormDataContent): T {
return apiClient.post() {
url {
encodedPath = path
contentType(ContentType.Application.FormUrlEncoded)
}
setBody(requestBody)
}.body()
}