Webpack 4 Plugin: Add module and get result from loader - webpack-4

I am making a Webpack 4 plugin for fun and to try to understand its internals. The idea is simple:
Parse an HTML template file into a tree;
Get the asset paths from <img src="..."> and <link href="...">;
Add the assets to dependencies to load them through the file-loader;
Get the path emitted from file-loader(which might include a hash)and fix the nodes in the tree;
Emit the final HTML string into a file.
So far, I am stuck at step 4. Parsing the template and extracting the asset paths was easy thanks to parse5, to load the assets, I used the PrefetchPlugin but now I don't know how to get the result from file-loader.
I need to load the result because it generates a hash and might change the location of the asset:
{
exclude: /\.(css|jsx?|mjs)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]?[sha512:hash:base64:8]`',
},
}],
}
Not only that, but I want to use the url-loader later which might generate the asset encoded. I am trying to get the result from the loader at tapAfterCompile.
The current source code for the plugin is as follows:
import debug from 'debug'
import prettyFormat from 'pretty-format'
import validateOptions from 'schema-utils'
import {dirname, resolve} from 'path'
import {html as beautifyHtml} from 'js-beautify'
import {minify as minifyHtml} from 'html-minifier'
import {parse, serialize} from 'parse5'
import {PrefetchPlugin} from 'webpack'
import {readFileSync} from 'fs'
let log = debug('bb:config:webpack:plugin:html')
const PLUGIN_NAME = 'HTML Plugin'
/**
* This schema is used to validate the plugin’s options, right now, all it does
* is requiring the template property.
*/
const OPTIONS_SCHEMA = {
additionalProperties: false,
type: 'object',
properties: {
minify: {
type: 'boolean',
},
template: {
type: 'string',
},
},
required: ['template'],
}
/**
* Extract an attribute’s value from the node; Returns undefined if the
* attribute is not found.
*/
function getAttributeValue(node, attributeName) {
for (let attribute of node.attrs) {
if (attribute.name === attributeName)
return attribute.value
}
return undefined
}
/**
* Update a node’s attribute value.
*/
function setAttributeValue(node, attributeName, value) {
for (let attribute of node.attrs) {
if (attribute.name === attributeName)
attribute.value = value
}
}
/**
* Recursively walks the parsed tree. It should work in 99.9% of the cases but
* it needs to be replaced with a non recursive version.
*/
function * walk(node) {
yield node
if (!node.childNodes)
return
for (let child of node.childNodes)
yield * walk(child)
}
/**
* Actual Webpack plugin that generates an HTML from a template, add the script
* bundles and and loads any local assets referenced in the code.
*/
export default class SpaHtml {
/**
* Options passed to the plugin.
*/
options = null
/**
* Parsed tree of the template.
*/
tree = null
constructor(options) {
this.options = options
validateOptions(OPTIONS_SCHEMA, this.options, PLUGIN_NAME)
}
/**
* Webpack will call this method to allow the plugin to hook to the
* compiler’s events.
*/
apply(compiler) {
let {hooks} = compiler
hooks.afterCompile.tapAsync(PLUGIN_NAME, this.tapAfterCompile.bind(this))
hooks.beforeRun.tapAsync(PLUGIN_NAME, this.tapBeforeRun.bind(this))
}
/**
* Return the extracted the asset paths from the tree.
*/
* extractAssetPaths() {
log('Extracting asset paths...')
const URL = /^(https?:)?\/\//
const TEMPLATE_DIR = dirname(this.options.template)
for (let node of walk(this.tree)) {
let {tagName} = node
if (!tagName)
continue
let assetPath
switch (tagName) {
case 'link':
assetPath = getAttributeValue(node, 'href')
break
case 'img':
assetPath = getAttributeValue(node, 'src')
break
}
// Ignore empty paths and URLs.
if (!assetPath || URL.test(assetPath))
continue
const RESULT = {
context: TEMPLATE_DIR,
path: assetPath,
}
log(`Asset found: ${prettyFormat(RESULT)}`)
yield RESULT
}
log('Done extracting assets.')
}
/**
* Returns the current tree as a beautified or minified HTML string.
*/
getHtmlString() {
let serialized = serialize(this.tree)
// We pass the serialized HTML through the minifier to remove any
// unnecessary whitespace that could affect the beautifier. When we are
// actually trying to minify, comments will be removed too. Options can be
// found in:
//
// https://github.com/kangax/html-minifier
//
const MINIFIER_OPTIONS = {
caseSensitive: false,
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
conservativeCollapse: false,
decodeEntities: true,
html5: true,
includeAutoGeneratedTags: false,
keepClosingSlash: false,
preserveLineBreaks: false,
preventAttributesEscaping: true,
processConditionalComments: false,
quoteCharacter: '"',
removeAttributeQuotes: true,
removeEmptyAttributes: true,
removeEmptyElements: false,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true,
useShortDoctype: true,
}
let {minify} = this.options
if (minify) {
// Minify.
serialized = minifyHtml(serialized, {
minifyCSS: true,
minifyJS: true,
removeComments: true,
...MINIFIER_OPTIONS,
})
} else {
// Beautify.
serialized = minifyHtml(serialized, MINIFIER_OPTIONS)
serialized = beautifyHtml(serialized, {
indent_char: ' ',
indent_inner_html: true,
indent_size: 2,
sep: '\n',
unformatted: ['code', 'pre'],
})
}
return serialized
}
/**
* Load the template and parse it using Parse5.
*/
parseTemplate() {
log('Loading template...')
const SOURCE = readFileSync(this.options.template, 'utf8')
log('Parsing template...')
this.tree = parse(SOURCE)
log('Done loading and parsing template.')
}
async tapAfterCompile(compilation, done) {
console.log()
console.log()
for (let asset of compilation.modules) {
if (asset.rawRequest == 'assets/logo.svg')
console.log(asset)
}
console.log()
console.log()
// Add the template to the dependencies to trigger a rebuild on change in
// watch mode.
compilation.fileDependencies.add(this.options.template)
// Emit the final HTML.
const FINAL_HTML = this.getHtmlString()
compilation.assets['index.html'] = {
source: () => FINAL_HTML,
size: () => FINAL_HTML.length,
}
done()
}
async tapBeforeRun(compiler, done) {
this.parseTemplate()
// Add assets to the compilation.
for (let {context, path} of this.extractAssetPaths()) {
new PrefetchPlugin(context, path)
.apply(compiler)
}
done()
}
}

Found the answer, after I loaded the dependencies, I can access the generated module's source:
// Index the modules generated in the child compiler by raw request.
let byRawRequest = new Map
for (let asset of compilation.modules)
byRawRequest.set(asset.rawRequest, asset)
// Replace the template requests with the result from modules generated in
// the child compiler.
for (let {node, request} of this._getAssetRequests()) {
if (!byRawRequest.has(request))
continue
const ASSET = byRawRequest.get(request)
const SOURCE = ASSET.originalSource().source()
const NEW_REQUEST = execAssetModule(SOURCE)
setResourceRequest(node, NEW_REQUEST)
log(`Changed: ${prettyFormat({from: request, to: NEW_REQUEST})}`)
}
And execute the module's source with a VM:
function execAssetModule(code, path) {
let script = new Script(code)
let exports = {}
let sandbox = {
__webpack_public_path__: '',
module: {exports},
exports,
}
script.runInNewContext(sandbox)
return sandbox.module.exports
}

Related

webpack5 asset module - [DEP_WEBPACK_MODULE_ISSUER] DeprecationWarning: Module.issuer: Use new ModuleGraph API

// webpack image rule
{
test: /\.(png|jpe?g|gif|bpm|svg|webp)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: function (source, { module }) {
if (/\.less|vue&type=style/.test(module.issuer.resource)) {
return true
}
return source.length < 8092
}
},
...
},
runing the config, I get this:
[DEP_WEBPACK_MODULE_ISSUER] DeprecationWarning: Module.issuer: Use new ModuleGraph API
it means need change code:
module.issuer.resource => compilation.moduleGraph.getIssuer(module).resource.
but parser.dataUrlCondition type is (source: Buffer, { module: Module, filename: string}) => boolean
if there a way to get current compilation that contain moduleGraph property?

Trouble Writing to Jest Mocked Prisma Database

I have two databases that I need to interact with in my code. I have a simple function that takes an object and writes it to my PostgreSQL database using Prisma. I've tested the function with Postman, and it works perfectly, but when I try to execute it using a Jest mock (using the singleton pattern found in the Prisma unit testing guide), it returns undefined indicating that it didn't interact with the database and create the new record. Here's my code:
/prisma/clinical-schema.prisma
generator client {
provider = "prisma-client-js"
output = "./generated/clinical"
}
datasource clinicalDatabase {
provider = "postgresql"
url = "postgresql://postgres:postgres#localhost:5432/clinical-data?schema=public"
}
model pcc_webhook_update {
id Int #id #default(autoincrement())
event_type String
organization_id Int
facility_id Int
patient_id Int
resource_id String?
webhook_date DateTime #default(now()) #clinicalDatabase.Timestamptz(6)
status pcc_webhook_update_status #default(pending)
status_changed_date DateTime? #clinicalDatabase.Timestamptz(6)
error_count Int #default(0)
##unique([organization_id, facility_id, patient_id, resource_id, event_type, status])
}
enum pcc_webhook_update_status {
pending
processing
processed
error
}
/prisma/clinical-client.ts
import { PrismaClient } from './generated/clinical';
const prismaClinical = new PrismaClient();
export default prismaClinical;
/testing/prisma-clinical-mock.ts
import { PrismaClient } from '../prisma/generated/clinical';
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended';
import prisma from '../prisma/clinical-client';
jest.mock('../prisma/clinical-client', () => ({
__esModule: true,
default: mockDeep<PrismaClient>()
}));
beforeEach(() => {
mockReset(prismaClinicalMock);
});
export const prismaClinicalMock = prisma as unknown as DeepMockProxy<PrismaClient>;
Everything up to this point follows the conventions outlined by the Prisma unit testing docs. The only modification I made was to make it database specific. Below is my function and tests. The request object in handle-pcc-webhooks.ts is a sample http request object, the body of which contains the webhook data I care about.
/functions/handle-pcc-webhooks/handler.ts
import prismaClinical from '../../../prisma/clinical-client';
import { pcc_webhook_update } from '../../../prisma/generated/clinical';
import { requestObject } from './handler.types';
export const handlePccWebhook = async (request: requestObject) => {
try {
const webhook = JSON.parse(request.body);
// if the webhook doesn't include a resource id array, set it to an array with an empty string to ensure processing and avoid violating
// the multi-column unique constraint on the table
const { resourceId: resourceIds = [''] } = webhook;
let records = [];
for (const resourceId of resourceIds) {
// update an existing record if one exists in the pending state, otherwise create a new entry
const record: pcc_webhook_update = await prismaClinical.pcc_webhook_update.upsert({
where: {
organization_id_facility_id_patient_id_resource_id_event_type_status: {
organization_id: webhook.orgId,
facility_id: webhook.facId,
patient_id: webhook.patientId,
resource_id: resourceId,
event_type: webhook.eventType,
status: 'pending'
}
},
update: {
webhook_date: new Date()
},
create: {
event_type: webhook.eventType,
organization_id: webhook.orgId,
facility_id: webhook.facId,
patient_id: webhook.patientId,
resource_id: resourceId,
status: 'pending' // not needed
}
});
records.push(record);
}
return records;
} catch (error) {
console.error(error);
}
};
/functions/handle-pcc-webhooks/handler.spec.ts
import fs from 'fs';
import path from 'path';
import MockDate from 'mockdate';
import { prismaClinicalMock } from '../../../testing/prisma-clinical-mock';
import { createAllergyAddRecord } from './__mocks__/allergy';
import { requestObject } from './handler.types';
import { handlePccWebhook } from './handler';
describe('allergy.add', () => {
let requestObject: requestObject;
let allergyAddRecord: any;
beforeAll(() => {
requestObject = getRequestObject('allergy.add');
});
beforeEach(() => {
MockDate.set(new Date('1/1/2022'));
allergyAddRecord = createAllergyAddRecord(new Date());
});
afterEach(() => {
MockDate.reset();
});
test('should create an allergy.add database entry', async() => {
prismaClinicalMock.pcc_webhook_update.create.mockResolvedValue(allergyAddRecord);
// this is where I would expect handlePccWebhook to return the newly created database
// record, but instead it returns undefined. If I run the function outside of this
// unit test, with the same input value, it functions perfectly
await expect(handlePccWebhook(requestObject)).resolves.toEqual([allergyAddRecord]);
});
});
// This just builds a request object with the current webhook being tested
function getRequestObject(webhookType: string) {
// read the contents of request object file as a buffer, then convert it to JSON
const rawRequestObject = fs.readFileSync(path.resolve(__dirname, '../../sample-data/handle-pcc-webhook-request.json'));
const requestObject: requestObject = JSON.parse(rawRequestObject.toString());
// read the contents of the webhook file as a buffer, then convert it to a string
const rawWebhook = fs.readFileSync(path.resolve(__dirname, `../../sample-data/${webhookType}.json`));
const webhookString = rawWebhook.toString();
// set the body of the request object to the contents of the target webhook
requestObject.body = webhookString;
return requestObject;
}
Finally, here is the result of running the unit test:
So after banging my had against the wall for a few hours, I figured out the issue. In my handler.spec.ts file, I had the following line:
prismaClinicalMock.pcc_webhook_update.create.mockResolvedValue(allergyAddRecord);
what that does is mock the value returned for any create functions run using Prisma. The issue is that my function is using an upsert function, which I wasn't explicitly mocking, thus returning undefined. I changed the above line to
prismaClinicalMock.pcc_webhook_update.upsert.mockResolvedValue(allergyAddRecord);
and it started working.

correctly set params in expo bottomtabs

Having a hard time understanding this newest expo bottom tabs
I dont see an initital params on the node_module for the bottomtabs or any params property... has anyone done this? essentially we have component for two bottom tabs and a different effect depending on that tab.
So 1. Can we pass Params into bottomTabs? 2. if so how?
error we get with TS is:
The expected type comes from property 'initialParams' which is declared here on type 'IntrinsicAttributes & RouteConfig<RootTabParamList, "TabThree", TabNavigationState, BottomTabNavigationOptions, BottomTabNavigationEventMap>'
<BottomTab.Screen
name="Episodes"
component={EpisodesScreen}
initialParams={{
type: "episodes",
}}
options={{
title: 'Episodes',
tabBarIcon: ({ color }) => <TabBarFeatherIcon name="headphones" color={color} />,
}}
/>
<BottomTab.Screen
name="TabThree"
component={EpisodesScreen}
initialParams={{
type: "quickGuides",
displayType: "grid",
}}
from the node_module::
import {
createNavigatorFactory,
DefaultNavigatorOptions,
ParamListBase,
TabActionHelpers,
TabNavigationState,
TabRouter,
TabRouterOptions,
useNavigationBuilder,
} from '#react-navigation/native';
import * as React from 'react';
import warnOnce from 'warn-once';
import type {
BottomTabNavigationConfig,
BottomTabNavigationEventMap,
BottomTabNavigationOptions,
} from '../types';
import BottomTabView from '../views/BottomTabView';
type Props = DefaultNavigatorOptions<
ParamListBase,
TabNavigationState<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
> &
TabRouterOptions &
BottomTabNavigationConfig;
function BottomTabNavigator({
initialRouteName,
backBehavior,
children,
screenListeners,
screenOptions,
sceneContainerStyle,
...restWithDeprecated
}: Props) {
const {
// #ts-expect-error: lazy is deprecated
lazy,
// #ts-expect-error: tabBarOptions is deprecated
tabBarOptions,
...rest
} = restWithDeprecated;
let defaultScreenOptions: BottomTabNavigationOptions = {};
if (tabBarOptions) {
Object.assign(defaultScreenOptions, {
tabBarHideOnKeyboard: tabBarOptions.keyboardHidesTabBar,
tabBarActiveTintColor: tabBarOptions.activeTintColor,
tabBarInactiveTintColor: tabBarOptions.inactiveTintColor,
tabBarActiveBackgroundColor: tabBarOptions.activeBackgroundColor,
tabBarInactiveBackgroundColor: tabBarOptions.inactiveBackgroundColor,
tabBarAllowFontScaling: tabBarOptions.allowFontScaling,
tabBarShowLabel: tabBarOptions.showLabel,
tabBarLabelStyle: tabBarOptions.labelStyle,
tabBarIconStyle: tabBarOptions.iconStyle,
tabBarItemStyle: tabBarOptions.tabStyle,
tabBarLabelPosition:
tabBarOptions.labelPosition ??
(tabBarOptions.adaptive === false ? 'below-icon' : undefined),
tabBarStyle: [
{ display: tabBarOptions.tabBarVisible ? 'none' : 'flex' },
defaultScreenOptions.tabBarStyle,
],
});
(
Object.keys(defaultScreenOptions) as (keyof BottomTabNavigationOptions)[]
).forEach((key) => {
if (defaultScreenOptions[key] === undefined) {
// eslint-disable-next-line #typescript-eslint/no-dynamic-delete
delete defaultScreenOptions[key];
}
});
warnOnce(
tabBarOptions,
`Bottom Tab Navigator: 'tabBarOptions' is deprecated. Migrate the options to
'screenOptions' instead.\n\nPlace the following in 'screenOptions' in your code to keep
current behavior:\n\n${JSON.stringify(
defaultScreenOptions,
null,
2
)}\n\nSee https://reactnavigation.org/docs/bottom-tab-navigator#options for more
details.`
);
}
if (typeof lazy === 'boolean') {
defaultScreenOptions.lazy = lazy;
warnOnce(
true,
`Bottom Tab Navigator: 'lazy' in props is deprecated. Move it to 'screenOptions'
instead.\n\nSee https://reactnavigation.org/docs/bottom-tab-navigator/#lazy for more
details.`
);
}
const { state, descriptors, navigation, NavigationContent } =
useNavigationBuilder<
TabNavigationState<ParamListBase>,
TabRouterOptions,
TabActionHelpers<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
>(TabRouter, {
initialRouteName,
backBehavior,
children,
screenListeners,
screenOptions,
defaultScreenOptions,
});
return (
<NavigationContent>
<BottomTabView
{...rest}
state={state}
navigation={navigation}
descriptors={descriptors}
sceneContainerStyle={sceneContainerStyle}
/>
</NavigationContent>
);
}
export default createNavigatorFactory<
TabNavigationState<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap,
typeof BottomTabNavigator
>(BottomTabNavigator);
only way i found to get my componenet to render on two different routes from the bottom tabs is to use the useNavigationState
import { useNavigationState } from "#react-navigation/native"
made a constant to check the route name and then on use effect we check the case...
const screenName = useNavigationState((state) =>
state.routes[state.index].name)
const type = screenName
useEffect(() => {
switch (type) {
case "Episodes":
setTitle("Episodes")
setIsLoading(false)
break
case "quickGuides":
setTitle("Quick Guides")
setIsLoading(false)
break
}
}, [])

getted data is only null in apollo-client / apollo-server & useSubscription

I try use pubsub in apollo server & apollo client. but subscribed data is only null.
client dependency
"#apollo/react-hooks": "^3.1.5",
"apollo-boost": "^0.4.9",
"apollo-link-ws": "^1.0.20",
"graphql": "^15.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"styled-components": "^5.1.1",
"subscriptions-transport-ws": "^0.9.16",
"typescript": "~3.7.2"
server dependency
"apollo-server": "^2.14.1",
"graphql": "^15.0.0",
"merge-graphql-schemas": "^1.7.8",
"ts-node": "^8.10.2",
"tsconfig-paths": "^3.9.0",
"typescript": "^3.9.3"
// apolloClient.ts
import { ApolloClient, HttpLink, InMemoryCache, split } from 'apollo-boost'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'
const wsLink = new WebSocketLink({
uri: 'ws://localhost:4000/graphql',
options: {
reconnect: true
}
})
const httpLink = new HttpLink({
uri: 'http://localhost:4000'
})
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
)
const cache = new InMemoryCache()
const client = new ApolloClient({
cache: cache,
link: link,
})
export default client
// subscribe.ts
const ON_PUT_UNIT = gql`
subscription onPutUnit($code: String!) {
onPutUnit(code: $code)
}
`
const onPutResult = useSubscription(
ON_PUT_UNIT,
{ variables: {
code: code,
}}
)
// in is only null!!
console.log('subscribe', onPutResult)
-server-
onPutUnit.ts
type Subscription {
onPutUnit(code: String!): Room
}
import { pubsub } from '#src/index'
const { withFilter } = require('apollo-server')
export default {
Subscription: {
onPutUnit: {
subscribe: withFilter(
() => pubsub.asyncIterator(['PUT_UNIT']),
(payload: any, variables: any) => {
// no problem in payload & variable data
return payload.code === variables.code
}
)
}
},
}
putUnit.ts
type Mutation {
putUnit(code: String!, x: Int!, y: Int!, userName: String!): Room!
}
export default {
Mutation: {
putUnit: async (_: any, args: args) => {
const { code, x, y, userName } = args
const room = findRoom(code)
console.log(room) // no problem. normal data.
pubsub.publish('PUT_UNIT', room)
return room
},
},
}
Is it some problem? subscribe event is normally reached to client when publish. but data is is only null. I can't fine the reason.
You only specified a subscribe function for onPutUnit, without specifying a resolve function. That means the field utilizes the default resolver.
The default resolver just looks for a property with the same name as the field on the parent object (the first parameter passed to the resolver) and returns that. If there is no property on the parent object with the same name as the field, then the field resolves to null. The parent object is the value the parent field resolved to. For example, if we have a query like this:
{
user {
name
}
}
whatever the resolver for user returns will be the parent value provided to the resolver for name (if user returns a Promise, it's whatever the Promise resolved to).
But what about user? It has no parent field because it's a root field. In this case, user is passed the rootValue you set when initializing the ApolloServer (or {} if you didn't).
With subscriptions, this works a bit differently because whatever value you publish is actually passed to the resolver as the root value. That means you can take advantage of the default resolver by publishing an object with a property that matches the field name:
pubsub.publish('PUT_UNIT', { onPutUnit: ... })
if you don't do that, though, you'll need to provide a resolve function that transforms the payload you published. For example, if we do:
pubsub.publish('PUT_UNIT', 'FOOBAR')
Then our resolver map needs to look something like this:
const resolvers = {
Subscription: {
onPutUnit: {
subscribe: ...,
resolve: (root) => {
console.log(root) // 'FOOBAR'
// return whatever you want onPutUnit to resolve to
}
}
},
}

Swagger codegen - swift 3 ignore params

There is a problem with header params in Swagger Codegen. my RAML file looks like that :
---...---
parameters:
timeParam_begin:
in: header
name: timeframe_begin
type: string
timeParam_end:
name: timeframe_end
in: header
type: string
recommendationsParam:
name: recommendations
in: header
default: 3
type: number
--- ....----
and later
---...----
post:
summary: Search for possible coordinates given an address
parameters:
- $ref: '#/parameters/timeParam_begin'
- $ref: '#/parameters/timeParam_end'
- $ref: '#/parameters/recommendationsParam'
---...----
Until here EVERYTHING IS GOOD, the validation is ok and the parameters works well.
But...
when I export it in swift (1,2 or3) there is a problem :
/**
- POST /tasks
- Add 'Task' object.
- examples: [{contentType=application/json, example="Task added succesfully"}]
- parameter task: (body) task object
- returns: RequestBuilder<String>
*/
open class func tasksPostWithRequestBuilder(task: Task) -> RequestBuilder<String> {
let path = "/tasks"
let URLString = SwaggerClientAPI.basePath + path
let parameters = task.encodeToJSON() as? [String:AnyObject]
let convertedParameters = APIHelper.convertBoolToString(parameters)
let requestBuilder: RequestBuilder<String>.Type = SwaggerClientAPI.requestBuilderFactory.getBuilder()
return requestBuilder.init(method: "POST", URLString: URLString, parameters: convertedParameters, isBody: true)
}
No more headers parameters !
I try to export it in PHP and typescript, the parameters are here !!!!! :
Typescript Angular2 :
/**
*
* Add 'Task' object.
* #param task task object
* #param timeframeBegin
* #param timeframeEnd
* #param recommendations
*/
public tasksPostWithHttpInfo(task: models.Task, timeframeBegin?: string, timeframeEnd?: string, recommendations?: number, extraHttpRequestParams?: any): Observable<Response> {
const path = this.basePath + `/tasks`;
let queryParameters = new URLSearchParams();
let headers = new Headers(this.defaultHeaders.toJSON()); // https://github.com/angular/angular/issues/6845
// verify required parameter 'task' is not null or undefined
if (task === null || task === undefined) {
throw new Error('Required parameter task was null or undefined when calling tasksPost.');
}
// to determine the Content-Type header
let consumes: string[] = [
'application/json'
];
// to determine the Accept header
let produces: string[] = [
'application/x-www-form-urlencoded'
];
headers.set('Content-Type', 'application/json');
let requestOptions: RequestOptionsArgs = new RequestOptions({
method: RequestMethod.Post,
headers: headers,
body: task == null ? '' : JSON.stringify(task), // https://github.com/angular/angular/issues/10612
search: queryParameters
});
// https://github.com/swagger-api/swagger-codegen/issues/4037
if (extraHttpRequestParams) {
requestOptions = this.extendObj(requestOptions, extraHttpRequestParams);
}
return this.http.request(path, requestOptions);
}
PHP :
/**
* Operation tasksPostWithHttpInfo
*
*
*
* #param \Swagger\Client\Model\Task $task task object (required)
* #param string $timeframe_begin (optional)
* #param string $timeframe_end (optional)
* #param float $recommendations (optional, default to 3.0)
* #throws \Swagger\Client\ApiException on non-2xx response
* #return array of string, HTTP status code, HTTP response headers (array of strings)
*/
public function tasksPostWithHttpInfo($task, $timeframe_begin = null, $timeframe_end = null, $recommendations = null)
{
// verify the required parameter 'task' is set
if ($task === null) {
throw new \InvalidArgumentException('Missing the required parameter $task when calling tasksPost');
}
// parse inputs
$resourcePath = "/tasks";
$httpBody = '';
$queryParams = [];
$headerParams = [];
$formParams = [];
$_header_accept = $this->apiClient->selectHeaderAccept(['application/x-www-form-urlencoded']);
if (!is_null($_header_accept)) {
$headerParams['Accept'] = $_header_accept;
}
$headerParams['Content-Type'] = $this->apiClient->selectHeaderContentType(['application/json']);
// header params
if ($timeframe_begin !== null) {
$headerParams['timeframe_begin'] = $this->apiClient->getSerializer()->toHeaderValue($timeframe_begin);
}
// header params
if ($timeframe_end !== null) {
$headerParams['timeframe_end'] = $this->apiClient->getSerializer()->toHeaderValue($timeframe_end);
}
// header params
if ($recommendations !== null) {
$headerParams['recommendations'] = $this->apiClient->getSerializer()->toHeaderValue($recommendations);
}
// default format to json
$resourcePath = str_replace("{format}", "json", $resourcePath);
// body params
$_tempBody = null;
if (isset($task)) {
$_tempBody = $task;
}
// for model (json/xml)
if (isset($_tempBody)) {
$httpBody = $_tempBody; // $_tempBody is the method argument, if present
} elseif (count($formParams) > 0) {
$httpBody = $formParams; // for HTTP post (form)
}
// make the API Call
try {
list($response, $statusCode, $httpHeader) = $this->apiClient->callApi(
$resourcePath,
'POST',
$queryParams,
$httpBody,
$headerParams,
'string',
'/tasks'
);
return [$this->apiClient->getSerializer()->deserialize($response, 'string', $httpHeader), $statusCode, $httpHeader];
} catch (ApiException $e) {
switch ($e->getCode()) {
case 200:
$data = $this->apiClient->getSerializer()->deserialize($e->getResponseBody(), 'string', $e->getResponseHeaders());
$e->setResponseObject($data);
break;
case 500:
$data = $this->apiClient->getSerializer()->deserialize($e->getResponseBody(), 'string', $e->getResponseHeaders());
$e->setResponseObject($data);
break;
}
throw $e;
}
}
WHY CODEGEN FAILS ????? please help. is there a way to force the generation of code ?