Skip to content

PHP API Generation Upgrade #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 61 commits into from
Feb 4, 2021
Merged

PHP API Generation Upgrade #4

merged 61 commits into from
Feb 4, 2021

Conversation

ashneilson
Copy link
Member

This is a partial re-write of the JS API Client Library to utilize a new JS Generator from the PHP API Project.

Included are fully JSDoc compliant comments for all Classes, Functions, Properties and Types.

TS Typings are Auto-Generated from the JSDoc comments and then bundled for Type-Script consumers to use.

ashneilson and others added 26 commits October 21, 2020 21:16
- Fixed an incorrect uses statement
- Ditched the jsdoc Action and instead install npm packages and build the docs ourselves.
- Incorrect docs on actions/setup-node for the @v2 release
@ashneilson ashneilson added the enhancement New feature or request label Oct 23, 2020
@ashneilson ashneilson requested review from sadsa and tainoNZ October 23, 2020 05:27
@ashneilson ashneilson self-assigned this Oct 23, 2020
@ashneilson
Copy link
Member Author

Hey @ashneilson . Currently, I'm using a property on the UserAccountModel called "hasPinCode" which seems to only be exposed on the private "_json" property. Is there any chance we can make this public?

@josh-biddick Sorry! I have no idea why, but I completely forgot to include the Non-Persisted Properties from the Model Schema in the JS Library Compiler!

Now resolved so you'll notice the hasPassword and hasPinCode properties are available on the UserAccountModel.

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ashneilson . The last comment I added, I somehow approved the PR and not sure how to undo an "approve". I think we are pretty much there, I would like however just clarify that my previous comment about Object Destructuring and Interfaces doesn't present any problems.

@ashneilson
Copy link
Member Author

Hey @ashneilson . The last comment I added, I somehow approved the PR and not sure how to undo an "approve". I think we are pretty much there, I would like however just clarify that my previous comment about Object Destructuring and Interfaces doesn't present any problems.

@josh-biddick No trouble man!

I've completed the fix for Optional Query Parameters. There is already an issue open on TypeScript relating to this: microsoft/TypeScript#39906

For now I have defined new types so the properties can be optional.

@ashneilson ashneilson requested a review from a user December 5, 2020 02:42
@ashneilson
Copy link
Member Author

@tainoNZ @josh-biddick I'm ready for this to be merged. Would be great if you both could review and provide any final comments.

package.json Outdated
"clean": "rimraf dist && rimraf dist_browser",
"build": "genversion --semi --es6 src/PackageVersion.js && tsc && cross-env babel src --out-dir dist && cross-env NODE_ENV=production webpack -p --config webpack.config.js",
"docs": "jsdoc -c jsdoc.json",
"prepublishOnly": "npm run types-lint && npm run clean && npm run build:browser && npm run docs",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm run build:browser no longer exists, Does it need to be changed to npm run build?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josh-biddick Great spotting mate!

Yes this should be changed to npm run build now 👍

@ashneilson ashneilson removed the request for review from tainoNZ December 8, 2020 04:50
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ashneilson,

I have a few questions in regard to the way we use and structure objects in the API.

Models

My first question is about Models. I see that many of the Models we use are simply JS classes which control access via "getter" methods to access thier private properties i.e. Site.name

One issue I'm currently experiencing is in the case where we want to combine two objects together. If we were working with standard POJO's (Plain Old Javascript Objects) for example, we could do something like this:

  const site = new Site();
  const siteWithAddedProperties = {
      ...site, <-- via spread operator 
    companyName: 'RICADO',
  };

However, the spread operator does not copy across public getter methods. Instead, when working with objects that have getters/setters, instead we would need to write something like this:

    const site = new Site();
    const siteWithAddedProperties = { 
      id: site.id, 
      name: site.name, 
      ... <- every member of site needs to be defined manually
    };
    siteWithAddedProperties.companyName = 'RICADO'

We can alternatively create a clone of the original site:

    const site = new Site();
    const siteWithAddedProperties = Object.assign(clone(site), { companyName: 'RICADO' })

Unfortunately Object.assign will instead set the property onto the newly cloned version of site. Meaning, that it's property accessors remain the same. Therfore, we couldn't then set new values because the original object only contained getter accessors.

Interfaces

The ability to use Interfaces to share common structure between two similar objects would be fantastic. For example, creating a new SiteDisplay object which extends the properties of Site.

interface ISiteDisplay extends ISiteModel {
  companyName: string;
}

Currently, because classes are being used in place of Interfaces, we must extend the Models.[ModelName] definitions as such:

interface ISiteDisplay extends Models.SiteModel {
  companyName: string;
}

This creates an issue, because our new ISiteDisplay interface is bound to Models.SiteModel and any object created using ISiteDisplay must implement the both the private and protected members :( .

"Interfaces inherit even the private and protected members of a base class. This means that when you create an interface that extends a class with private or protected members, that interface type can only be implemented by that class or a subclass of it".

You can read more here - https://www.typescriptlang.org/docs/handbook/interfaces.html#interfaces-extending-classes

So, anytime we want to create a new object that inherit properties from it's parent, we also carry the burden of those children objects potentially breaking any time there's a change in the parent class.

Are we able to decorate our Model classes with Interfaces to give us greater flexibility? Or perhaps even remove the concept of Models altogether and just have the Controllers return data that match these Interfaces? e.g.

function createSite(): Promise<ISiteModel> {
	return Controllers.SiteController.create();
}

As for the newly addedfromJSON method - this could simply be moved to the respective Controller class.

Let me know you're thoughts. Hopefully I haven't thrown a spanner in the works :)

@ashneilson
Copy link
Member Author

@josh-biddick Thanks for the feedback and raising this.

I'm wondering if we'd be best to get started using the API Client in it's current form and look to introduce improvements in the future?

Interfaces would help, I understand that, but they are a TypeScript concept and wouldn't be useful for consumers using JavaScript (many of our Apps are still JS only).

We could move the Model fromJSON() into the Controller, it would just require a bit of re-writing the PHP API Generation codebase.

I'll have a review and come back to you.

@ghost
Copy link

ghost commented Dec 14, 2020

@ashneilson - Okay, that's fine. For now that will mean that I will need to create these Interfaces myself and centralise them somewhere until such time that we support them within the JS API Client. It's not so much a question of supporting Typescript as it is following SOLID priniciples that span all OOP languages (PHP included). I don't want us to get in a situation where we can't scale as the number of Models grow.

@ghost
Copy link

ghost commented Feb 2, 2021

@ashneilson - Is there still work to be done on this or are you happy to merge this into master?

@ashneilson
Copy link
Member Author

@josh-biddick I'd love to get this merged in so we can start implementing and testing in our Gen 4 Apps.

I'm wondering if any of your requested changes need to be made before we do this?

@ghost
Copy link

ghost commented Feb 3, 2021

@ashneilson - Yup, I'm happy with that. As I mentioned, this will mean that for now, these interfaces/types will be defined in our Gen4 Apps using Typescript. Let's be aware that this does require code in two places should the underlying model structures change. I'll make a task in Wrike to revisit this for the future.

@ashneilson ashneilson requested a review from a user February 4, 2021 01:45
@ashneilson ashneilson merged commit 1e8ba73 into master Feb 4, 2021
@ashneilson ashneilson deleted the api-generation-upgrade branch February 4, 2021 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants