This might look like a stupid question but i am struggling hard, to get this working. Here are a few details, I want to share with you, so you might have a better understanding of what I mean. First of all, i'm just trying to learn coding and I try to implement what I learnt in a small project for myself. Please bear with me :)
Current Setup
I am fetching an external API Endpoint, where the json looks like this:
{
"orders": [
{
"input": {
"amount": "1",
"currency": "EUR",
"type": "bank_account",
"iban": "DEXXX"
},
"output": {
"amount": "2",
"currency": "CHF",
"type": "paypal",
"paypal_recipient": "example@example.org"
},
"id": "8e150ca6",
"timestamp_created": "2021-06-06T20:34:19.827Z",
"timestamp_executed": "2021-06-07T06:43:57Z",
"timestamp_awaiting_payment_since": "2021-06-06T20:34:28.921Z",
"timestamp_payment_received": "2021-06-07T06:43:57Z",
"payment_details": {
"iban": "DEXXX",
"recipient_name": "Company1",
"recipient_postal_address": [
"Maxstreet",
"1000 Berlin ",
"Germany"
],
"reference": "Order XY",
"swift_bic": "BCNNXX",
"type": "bank_account"
},
"price_breakdown": {
"customer_trading_fee": {
"amount": "1.56",
"currency": "EUR"
},
"non-verified_fee": {
"amount": "0.79",
"currency": "EUR"
},
"partner_fee": {
"amount": "3.4",
"currency": "EUR"
}
}
},
{
"input": {.....
},
"pagination": {
"current": 1,
"first": 1,
"last": 1
}
}
I have several Structs, which does reprint, how the json is built:
Type OrderStructDB struct {
gorm.Model
OrderID string `gorm:"unique;not null"`
TimestampCreated time.Time `json:"timestamp_created"`
TimestampCancelled time.Time `json:"timestamp_cancelled"`
TimestampAwaitingPaymentSince time.Time `json:"timestamp_awaiting_payment_since"`
InputStructID uint `gorm:"foreignKey:InputStruct"`
InputStruct InputStruct
OutputStructID uint `gorm:"foreignKey:OutputStruct"`
OutputStruct OutputStruct
PriceBreakdownStructID uint `gorm:"foreignKey:PriceBreakdownStruct"`
PriceBreakdownStruct PriceBreakdownStruct
//PaymentDetailsStructID uint `gorm:"foreignKey:PaymentDetailsStruct"`
//PaymentDetailsStruct PaymentDetailsStruct
}
type OrderStruct struct {
Input InputStruct `json:"input" ,gorm:"foreignKey:ID"`
Output OutputStruct `json:"output" ,gorm:"foreignKey:ID"`
OrderID string `json:"id" ,gorm:"unique;not null"`
TimestampCreated time.Time `json:"timestamp_created"`
TimestampCancelled time.Time `json:"timestamp_cancelled"`
TimestampAwaitingPaymentSince time.Time `json:"timestamp_awaiting_payment_since"`
PaymentDetails PaymentDetailsStruct `json:"payment_details" ,gorm:"embedded;embeddedPrefix:paymentdetails_,foreignKey:ID"`
PriceBreakdown PriceBreakdownStruct `json:"price_breakdown" ,gorm:"embedded;embeddedPrefix:pricebreakdown_,foreignKey:ID"`
MessageToSign MessageToSignStruct `json:"message_to_sign,omitempty"`
//PaymentDetailsStructID uint `gorm:"foreignKey:PaymentDetailsStruct"`
//PaymentDetailsStruct PaymentDetailsStruct
}
type InputStruct struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
Type string `json:"type"`
Iban string `json:"iban"`
gorm.Model
}
type OutputStruct struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
Type string `json:"type"`
CryptoAddress string `json:"crypto_address"`
gorm.Model
}
type PaymentDetailsStruct struct {
Iban string `json:"iban"`
RecipientName string `json:"recipient_name"`
RecipientPostalAddress []string `json:"recipient_postal_address"`
Reference string `json:"reference"`
SwiftBic string `json:"swift_bic"`
Type string `json:"type"`
}
type CustomerTradingFeeStruct struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
gorm.Model
}
type PriceBreakdownStruct struct {
CustomerTradingFeeID uint `gorm:"foreignKey:CustomerTradingFee"`
CustomerTradingFee CustomerTradingFeeStruct `json:"customer_trading_fee" ,gorm:"references:PriceBreakdownID"`
NonVerifiedFeeID uint `gorm:"foreignKey:NonVerifiedFee"`
NonVerifiedFee NonVerifiedFeeStruct `json:"non-verified_fee" ,gorm:"references:PriceBreakdownID"`
PartnerFeeID uint `gorm:"foreignKey:ParnterFee"`
PartnerFee PartnerFeeStruct `json:"partner_fee" ,gorm:"references:PriceBreakdownID"`
gorm.Model
}
type MessageToSignStruct struct {
Body string `json:"body"`
SignatureSubmissionURL string `json:"signature_submission_url"`
}
type NonVerifiedFeeStruct struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
gorm.Model
}
type PartnerFeeStruct struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
gorm.Model
}
type OrdersStruct struct {
Orders []OrderStruct `json:"orders"`
Pagination PaginationStruct `json:"pagination"`
}
type PaginationStruct struct {
Current int `json:"current"`
First int `json:"first"`
Last int `json:"last"`
}
What I have managed so far is:
- I can Unmarshal the Rest Response into my current Structs
- I can print all Orders on to the console
- I can Query a single Order and map it directly into "OrderStruct"
- I can map "OrderStruct" into "OrderStructDB" and write that single Order into the Database (It also works with the database relations so far)
Where I Am struggling
I'm really not sure, how i can use the "OrdersStruct", with a nested Slice of "OrderStruct" and write the same details to the database as described in "OrderStructDB". I tried a few variants but i couldn't get it working after hours.
Here's what the codepart looks like for getting a single order and write it to the db:
func getOrder() (Order OrderStruct) {
conf := getToken()
client := conf.Client(context.Background())
res, err := client.Get("https://api.endpoint/v1/orders/baa1f5f4")
if err != nil {
log.Fatal(err.Error())
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err.Error())
}
var formattedBody OrderStruct
err = json.Unmarshal(body, &formattedBody)
if err != nil {
log.Fatal(err.Error())
}
// Create DB Entry Logic and Struct
// Connect DB
db := helpers.ConnectDB()
order := OrderStructDB{
OrderID: formattedBody.OrderID,
InputStruct: formattedBody.Input,
OutputStruct: formattedBody.Output,
PriceBreakdownStruct: formattedBody.PriceBreakdown,
TimestampCreated: formattedBody.TimestampCreated,
TimestampCancelled: formattedBody.TimestampCancelled,
TimestampAwaitingPaymentSince: formattedBody.TimestampAwaitingPaymentSince,
}
err = db.Create(&order).Error
if err, ok := err.(*pq.Error); ok && err.Code.Name() == "unique_violation" {
helpers.HandleErr(err)
// handle error
}
defer db.Close()
return formattedBody
}
And here's the snippet, on where I fetch all the orders, but have not managed to get it into the database. I've deleted all attempts, trying to get it into the db tho:
func getOrders() (Orders OrdersStruct) {
conf := getToken()
client := conf.Client(context.Background())
res, err := client.Get("https://api.endpoint/v1/orders")
if err != nil {
log.Fatal(err.Error())
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err.Error())
}
var formattedBody OrdersStruct
err = json.Unmarshal(body, &formattedBody)
helpers.HandleErr(err)
// Connect DB
db := helpers.ConnectDB()
//Define the StructMapping, my problem lies probably here. How to map the details of slice struct into a struct, i can map into the databse
err = db.Create(&orders).Error
if err, ok := err.(*pq.Error); ok && err.Code.Name() == "unique_violation" {
helpers.HandleErr(err)
// handle error
}
defer db.Close()
return formattedBody
}
I've added a small comment to the section, i believe i have the error. I want to put the elements of the OrdersStruct into the OrderStructDB, as I want the information stored to be the same as the single order one. But I can't manage to get it nearly working. I tried several methods like:
orders := OrderStructDB{
OrderID: formattedBody.Orders.OrderID,
InputStruct: formattedBody.Orders.Input,
OutputStruct: formattedBody.Orders.Output,
PriceBreakdownStruct: formattedBody.Orders.PriceBreakdown,
TimestampCreated: formattedBody.Orders.TimestampCreated,
TimestampCancelled: formattedBody.Orders.TimestampCancelled,
TimestampAwaitingPaymentSince: formattedBody.Orders.TimestampAwaitingPaymentSince,
}
But i keep failing here. I am not sure, what is the best way to achieve that. Do I maybe need to create also a new OrdersStructDB Type. I thought of bulk inserting, but do I maybe need to loop through the slice and create my new slice, without the "top-level-elements" of the json?
I'd be so thankful to get a few insights and hints, on where my brain is stopping to work, where i am thinking in the wrong direction.
Happy to share also more Code if that would be helpful for you.
Thanks and thankfully,
a guy who tries to learn to code