Open RJPearson94 opened 3 years ago
@RJPearson94
Thank you for the in depth issue and details! A corresponding issue in twilio-oai would be appreciated to outline the missing request body schema. We are aware our library doesn't currently support JSON ingress but it's definitely on the horizon! We'd greatly appreciate any PR you're willing to submit (even as a proof-of-concept) to support our effort. If you're submitting PRs to multiple repos (i.e. one for updating mustache templates here, plus any corresponding changes in twilio-go) please be sure they include links to each other in the description. This issue has been added to our internal backlog to be prioritized. Pull requests and +1s on the issue summary will help it move up the backlog.
Thanks @eshanholtz, I'll take a look at putting together a few PRs. I'll get the issue raised on the twilio-oai repo too
Hi @eshanholtz,
Apologies for the delay in raising these PRs.
I have raised 2 PR's (twilio/twilio-go#83 and twilio/twilio-go#84) against the Go SDK repo and 1 PR against this repo (#54) to lay the groundwork for resolving this issue. Unfortunately, until twilio/twilio-oai#36 is resolved, Flex Configuration cannot be updated via the Go SDK.
I have tested this locally by replacing the operations for the /v1/Configuration
path in the Flex OpenAPI spec YAML file with the YAML below
/v1/Configuration:
description: Configuration for a Flex instance
get:
description: ''
operationId: FetchConfiguration
parameters:
- description: The Pinned UI version of the Configuration resource to fetch.
in: query
name: UiVersion
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/flex.v1.configuration'
description: OK
security:
- accountSid_authToken: []
x-maturity:
- GA
post:
description: ''
operationId: UpdateConfiguration
requestBody:
content:
application/json:
schema:
properties:
account_sid:
description: The SID of the Account that created the resource
maxLength: 34
minLength: 34
nullable: false
pattern: ^AC[0-9a-fA-F]{32}$
type: string
attributes:
description: An object that contains application-specific data
nullable: true
type: object
call_recording_enabled:
description: Whether call recording is enabled
nullable: true
type: boolean
call_recording_webhook_url:
description: The call recording webhook URL
format: uri
nullable: true
type: string
chat_service_instance_sid:
description: The SID of the chat service this user belongs to
maxLength: 34
minLength: 34
nullable: true
pattern: ^IS[0-9a-fA-F]{32}$
type: string
crm_attributes:
description: An object that contains the CRM attributes
nullable: true
type: object
crm_callback_url:
description: The CRM Callback URL
format: uri
nullable: true
type: string
crm_enabled:
description: Whether CRM is present for Flex
nullable: true
type: boolean
crm_fallback_url:
description: The CRM Fallback URL
format: uri
nullable: true
type: string
crm_type:
description: The CRM Type
nullable: true
type: string
date_created:
description: The ISO 8601 date and time in GMT when the Configuration resource
was created
format: date-time
nullable: true
type: string
date_updated:
description: The ISO 8601 date and time in GMT when the Configuration resource
was last updated
format: date-time
nullable: true
type: string
integrations:
description: A list of objects that contain the configurations for the Integrations
supported in this configuration
items:
type: object
nullable: true
type: array
markdown:
description: Configurable parameters for Markdown
nullable: true
type: object
messaging_service_instance_sid:
description: The SID of the Messaging service instance
maxLength: 34
minLength: 34
nullable: true
pattern: ^MG[0-9a-fA-F]{32}$
type: string
notifications:
description: Configurable parameters for Notifications
nullable: true
type: object
outbound_call_flows:
description: The list of outbound call flows
nullable: true
type: object
plugin_service_attributes:
description: The plugin service attributes
nullable: true
type: object
plugin_service_enabled:
description: Whether the plugin service enabled
nullable: true
type: boolean
public_attributes:
description: The list of public attributes
nullable: true
type: object
queue_stats_configuration:
description: Configurable parameters for Queues Statistics
nullable: true
type: object
runtime_domain:
description: The URL where the Flex instance is hosted
format: uri
nullable: true
type: string
serverless_service_sids:
description: The list of serverless service SIDs
items:
maxLength: 34
minLength: 34
pattern: ^ZS[0-9a-fA-F]{32}$
type: string
nullable: true
type: array
taskrouter_skills:
description: The Skill description for TaskRouter workers
items:
type: object
nullable: true
type: array
taskrouter_target_taskqueue_sid:
description: The SID of the TaskRouter Target TaskQueue
maxLength: 34
minLength: 34
nullable: true
pattern: ^WQ[0-9a-fA-F]{32}$
type: string
taskrouter_target_workflow_sid:
description: The SID of the TaskRouter target Workflow
maxLength: 34
minLength: 34
nullable: true
pattern: ^WW[0-9a-fA-F]{32}$
type: string
taskrouter_taskqueues:
description: The list of TaskRouter TaskQueues
items:
type: object
nullable: true
type: array
taskrouter_worker_attributes:
description: The TaskRouter Worker attributes
nullable: true
type: object
taskrouter_worker_channels:
description: The TaskRouter default channel capacities and availability
for workers
nullable: true
type: object
ui_attributes:
description: The object that describes Flex UI characteristics and settings
nullable: true
type: object
ui_dependencies:
description: The object that defines the NPM packages and versions to be
used in Hosted Flex
nullable: true
type: object
ui_language:
description: The primary language of the Flex UI
nullable: true
type: string
ui_version:
description: The Pinned UI version
nullable: true
type: string
title: UpdateFlexConfigurationRequest
type: object
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/flex.v1.configuration'
description: OK
security:
- accountSid_authToken: []
x-maturity:
- GA
servers:
- url: https://flex-api.twilio.com
x-twilio:
defaultOutputProperties:
- status
- ui_language
- ui_version
- service_version
pathType: instance
With this updated spec, the following code was generated for the Go SDK
// rest/flex/v1/api_defaults.go
...
// Optional parameters for the method 'UpdateConfiguration'
type UpdateConfigurationParams struct {
//
UpdateFlexConfigurationRequest *UpdateFlexConfigurationRequest `json:"UpdateFlexConfigurationRequest,omitempty"`
}
func (params *UpdateConfigurationParams) SetUpdateFlexConfigurationRequest(UpdateFlexConfigurationRequest UpdateFlexConfigurationRequest) *UpdateConfigurationParams {
params.UpdateFlexConfigurationRequest = &UpdateFlexConfigurationRequest
return params
}
func (c *DefaultApiService) UpdateConfiguration(params *UpdateConfigurationParams) (*FlexV1Configuration, error) {
path := "/v1/Configuration"
var data UpdateFlexConfigurationRequest
if params.UpdateFlexConfigurationRequest != nil {
data = *params.UpdateFlexConfigurationRequest
} else {
data = UpdateFlexConfigurationRequest{}
}
headers := make(map[string]interface{})
resp, err := c.requestHandler.PostJson(c.baseURL+path, data, headers)
if err != nil {
return nil, err
}
defer resp.Body.Close()
ps := &FlexV1Configuration{}
if err := json.NewDecoder(resp.Body).Decode(ps); err != nil {
return nil, err
}
return ps, err
}
...
// rest/flex/v1/model_update_flex_configuration_request.go
/*
* Twilio - Flex
*
* This is the public Twilio REST API.
*
* API version: 1.16.1
* Contact: support@twilio.com
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package openapi
import (
"time"
)
// UpdateFlexConfigurationRequest struct for UpdateFlexConfigurationRequest
type UpdateFlexConfigurationRequest struct {
// The SID of the Account that created the resource
AccountSid *string `json:"account_sid,omitempty"`
// An object that contains application-specific data
Attributes *map[string]interface{} `json:"attributes,omitempty"`
// Whether call recording is enabled
CallRecordingEnabled *bool `json:"call_recording_enabled,omitempty"`
// The call recording webhook URL
CallRecordingWebhookUrl *string `json:"call_recording_webhook_url,omitempty"`
// The SID of the chat service this user belongs to
ChatServiceInstanceSid *string `json:"chat_service_instance_sid,omitempty"`
// An object that contains the CRM attributes
CrmAttributes *map[string]interface{} `json:"crm_attributes,omitempty"`
// The CRM Callback URL
CrmCallbackUrl *string `json:"crm_callback_url,omitempty"`
// Whether CRM is present for Flex
CrmEnabled *bool `json:"crm_enabled,omitempty"`
// The CRM Fallback URL
CrmFallbackUrl *string `json:"crm_fallback_url,omitempty"`
// The CRM Type
CrmType *string `json:"crm_type,omitempty"`
// The ISO 8601 date and time in GMT when the Configuration resource was created
DateCreated *time.Time `json:"date_created,omitempty"`
// The ISO 8601 date and time in GMT when the Configuration resource was last updated
DateUpdated *time.Time `json:"date_updated,omitempty"`
// A list of objects that contain the configurations for the Integrations supported in this configuration
Integrations *[]map[string]interface{} `json:"integrations,omitempty"`
// Configurable parameters for Markdown
Markdown *map[string]interface{} `json:"markdown,omitempty"`
// The SID of the Messaging service instance
MessagingServiceInstanceSid *string `json:"messaging_service_instance_sid,omitempty"`
// Configurable parameters for Notifications
Notifications *map[string]interface{} `json:"notifications,omitempty"`
// The list of outbound call flows
OutboundCallFlows *map[string]interface{} `json:"outbound_call_flows,omitempty"`
// The plugin service attributes
PluginServiceAttributes *map[string]interface{} `json:"plugin_service_attributes,omitempty"`
// Whether the plugin service enabled
PluginServiceEnabled *bool `json:"plugin_service_enabled,omitempty"`
// The list of public attributes
PublicAttributes *map[string]interface{} `json:"public_attributes,omitempty"`
// Configurable parameters for Queues Statistics
QueueStatsConfiguration *map[string]interface{} `json:"queue_stats_configuration,omitempty"`
// The URL where the Flex instance is hosted
RuntimeDomain *string `json:"runtime_domain,omitempty"`
// The list of serverless service SIDs
ServerlessServiceSids *[]string `json:"serverless_service_sids,omitempty"`
// The Skill description for TaskRouter workers
TaskrouterSkills *[]map[string]interface{} `json:"taskrouter_skills,omitempty"`
// The SID of the TaskRouter Target TaskQueue
TaskrouterTargetTaskqueueSid *string `json:"taskrouter_target_taskqueue_sid,omitempty"`
// The SID of the TaskRouter target Workflow
TaskrouterTargetWorkflowSid *string `json:"taskrouter_target_workflow_sid,omitempty"`
// The list of TaskRouter TaskQueues
TaskrouterTaskqueues *[]map[string]interface{} `json:"taskrouter_taskqueues,omitempty"`
// The TaskRouter Worker attributes
TaskrouterWorkerAttributes *map[string]interface{} `json:"taskrouter_worker_attributes,omitempty"`
// The TaskRouter default channel capacities and availability for workers
TaskrouterWorkerChannels *map[string]interface{} `json:"taskrouter_worker_channels,omitempty"`
// The object that describes Flex UI characteristics and settings
UiAttributes *map[string]interface{} `json:"ui_attributes,omitempty"`
// The object that defines the NPM packages and versions to be used in Hosted Flex
UiDependencies *map[string]interface{} `json:"ui_dependencies,omitempty"`
// The primary language of the Flex UI
UiLanguage *string `json:"ui_language,omitempty"`
// The Pinned UI version
UiVersion *string `json:"ui_version,omitempty"`
}
I have tested the modified UpdateConfiguration
function using the example code below and the code works as expected.
package main
import (
"log"
"os"
"github.com/twilio/twilio-go"
openapi "github.com/twilio/twilio-go/rest/flex/v1"
)
func main() {
client := twilio.NewRestClient(os.Getenv("TWILIO_ACCOUNT_SID"), os.Getenv("TWILIO_AUTH_TOKEN"))
resp, err := client.FlexV1.UpdateConfiguration(&openapi.UpdateConfigurationParams{
UpdateFlexConfigurationRequest: &openapi.UpdateFlexConfigurationRequest{
AccountSid: PtrString(os.Getenv("TWILIO_ACCOUNT_SID")),
},
})
if err != nil {
log.Panic(err.Error())
}
log.Printf("SID: %s", StringValue(resp.FlexServiceInstanceSid))
}
// PtrString is a utility method for obtaining a pointer for a value
func PtrString(value string) *string {
return &value
}
// StringValue is a utility method for obtaining the string value of a pointer
func StringValue(value *string) string {
return *value
}
Any feedback is greatly appreciated
Issue Summary
Hi, I have noticed that you cannot currently update a Twilio Flex instance configuration using the Twilio Go SDK. Currently on every POST request the
Content-Type
header is hardcoded to beapplication/x-www-form-urlencoded
as seen here This is suitable for the majority of POST requests to the various Twilio API however to update the Flex Configuration, JSON needs to be sent in the request body.To fix this I believe it will require changes in the Go SDK with the request handler and client being modified. Changes will also be required inside of the API mustache template in this repo.
I was thinking that inside the request handler in the Go SDK, the current Post function would be updated to create a new map that combines the
Content-Type
header (with the value ofapplication/x-www-form-urlencoded
) with the header map which is passed into the function. I was going with this approach to prevent mutating the headers map but if you want the header can either be passed in as another argument to SendRequest or the value could be appended to the headers map. The current logic to set theContent-Type
header inside of send request would be deleted. Another functionPostJson
would be added which would accept the path, body (of typemap[string]interface{}
) and the headers. This function would set the value of theContent-Type
header toapplication/json
.In the generator, the API mustache template file will be updated to check if the request media type is
application/json
then the initialization of the data map (url.Values) and population of the params data into the map will be replaced with the params struct being marshalled into a map of typemap[string]interface{}
using the build-inMarshal
function in thejson
package. Instead of the Post function being called on the request handler the PostJson function will be called. If the request media type is not supplied or isapplication/x-www-form-urlencoded
then the current implementation will be used, as per the current implementation.The JSON and YML Open API templates don't currently include the request body schema which would be used to generate the input/ params struct, so the changes outlined above will resolve the issue highlighted however the Flex configuration cannot be updated using the SDK until the definition has been updated. As this is an issue with the Open API templates do you want the issue for this raised on the twilio-oai repo?
This implementation should be flexible enough to be replicated to add support for creating a Serverless Asset Version and creating a Serverless Function Version via the SDK, both of which require form data to be supplied.
If you are happy with the changes I am happy to raise a PR for this.
Steps to Reproduce
Code Snippet
Exception/Log
Technical details: