Skip to content

Make endpoint and request options configurable. #28

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

Conversation

robertatcd
Copy link
Contributor

These changes allow the client to be used with other Unleash servers.

My use case is GitLab: I need to be able to specify the feature flags endpoint for a particular project, and I need to pass two headers to identify the environment and the instance.

So in my own .env I have:

UNLEASH_URL="https://{our GitLab server}"
UNLEASH_FEATURES_ENDPOINT="/api/v4/feature_flags/unleash/{my project id}/features"

And in my config/unleash.php:

  'request_options' => [
    'headers' => [
        'UNLEASH-APPNAME' => 'local',
        'UNLEASH-INSTANCEID' => '{my instance id}',
    ]
  ],

@mxkxf
Copy link
Collaborator

mxkxf commented Apr 8, 2021

Hi @robertatcd, thanks for this.

I'm just wondering how common this feature is?

If this is something very specific to you or your project, it may be better for you to maintain a fork of this.

@robertatcd
Copy link
Contributor Author

Hi @mikefrancis

I found I needed to extend this in order to use the feature flag facility provided by GitLab, which I image will be fairly common.

It uses the same headers as specified in the Unleash docs:

https://docs.getunleash.io/docs/api/client/features

While developing this, I had assumed this was something that was mainly intended for use with servers that host flag sets for multiple projects, and so it would also be required if you were accessing the hosted service run by Unleash themselves:

https://www.unleash-hosted.com/open-source/

But looking at the docs again, I see they're not specific to that hosted service. They almost seem mandatory. So I'm wondering what contexts don't require them? I guess I'm missing something? (I'm new to Unleash and only starting to dabble in feature flags.)

@robertatcd
Copy link
Contributor Author

Ah yes, here's the reason I thought the APPNAME and INSTANCEID headers were associated with the hosted Unleash service: they are configurable options in (at least some of) the SDKs mentioned on their site: https://www.unleash-hosted.com/demo/connect/#java

@mxkxf
Copy link
Collaborator

mxkxf commented Apr 8, 2021

Ah ok, I see now - thanks for the docs!

I think rather than making the whole request options configurable, what if we set these 2 headers if the respected config options exist?

@ppx17
Copy link

ppx17 commented Apr 16, 2021

Explicit options are a bit more in line with how other clients (Java & Go) do it.In addition, the Java client also allows you to add custom headers, in case you host your instance behind a proxy that requires auth etc.

In my opinion, the way that is implemented in this PR is still very clear and easy to configure, so I would opt not to add the extra complexity of explicit options and then still needing this to provide potential additional headers.

PS. I'm also a Gitlab user that needs these precise options to use this library.

kalebdueck
kalebdueck previously approved these changes Apr 16, 2021
@kalebdueck
Copy link

This would be a great addition, coming from the gitlab side as well.

@dshafik
Copy link
Contributor

dshafik commented Apr 26, 2021

I was also looking into this for our multi-application -> unleash setup: +1 here

@mxkxf
Copy link
Collaborator

mxkxf commented Apr 26, 2021

My main reservation with the implementation here is that HTTP was originally completely separate from the Unleash service singleton and we're starting to see a lot of HTTP things bleeding into the Unleash service.

I think we may need to rethink where the HTTP options are coming from/can be configured.

Other than that, the reasoning makes complete sense - I did wonder why a lot of GitLab people were turning up 😅

@robertatcd
Copy link
Contributor Author

(Apologies for not getting back to this until now).

@mikefrancis I'm still leaning towards the headers being configurable options. As @ppx17 commented, it makes them completely configurable. It should cover cases like proxies, other server implementations that need different headers, etc.

For the same reason, I made the API endpoint configurable rather than it being hardcoded to api/client/features, as that's needed in GitLab (for one example) to select between multiple projects.

I take your point about all the HTTP stuff being in the Unleash service though. Did you have anything in mind for refactoring it out?

@mxkxf
Copy link
Collaborator

mxkxf commented May 10, 2021

@robertatcd I agree, let's make the headers configurable!

I think we could make use of the client initialisation here to set any headers that are set in config:

https://github.com/mikefrancis/laravel-unleash/blob/master/src/Client.php#L12-L16

Does that make sense?

@evanshriner
Copy link

definitely need this endpoint configurable in our setup. +1

@@ -5,6 +5,13 @@
// This should be the base URL, do not include /api or anything else.
'url' => env('UNLEASH_URL'),

// Endpoint for accessing feature flags, on the Unleash server.
'features_endpoint' => env('UNLEASH_FEATURES_ENDPOINT', '/api/client/features'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

We're using camelCase for the keys in this file. I don't think it's the actual Laravel convention but we should be consistent in this package

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ffee84d85bc676ac5309c7a6ca14b5c23f0642b7

+ move base_uri into requestDefaults config setting
+ use requestDefaults config setting when instantiating the client
+ retain the features endpoint as a separate config setting, in case the client is used to make different requests to different endpoints in the future.
@robertatcd
Copy link
Contributor Author

Wow, where did that month go? Apologies for the long delay again.

@mikefrancis I hope this change is in line with what you were thinking, re: making use of the client initialisation.

I have bundled the url/base_uri setting into a general requestDefaults setting, which is used in the client initialisation.

At the suggestion of a colleague, I refrained from my initial approach of also tacking the features endpoint onto the end of base_uri, because that would make the features endpoint specifically the default for the client. His reasoning was that you may want to use that client to access other endpoints on the Unleash server in the future, so it's better to keep that config setting separate, and make use of it in the ->get() call in fetchFeatures().

@@ -10,9 +10,7 @@ class Client extends GuzzleClient
public function __construct(Config $config)
{
parent::__construct(
[
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we may need to do a bit of merging of the config here as by removing the unleash.url we are not making this backwards compatible.

I am not sure this feature warrants an entire new major version, so I'm just wondering if there's anything clever we could do to fall back to unleash.url if unleash.requestDefaults doesn't exist? Does this make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh yes, good point.

I have been hit twice this week by unheralded breaking changes, so I'm very sympathetic to that!

Updated to return unleash.url to its original spot.

@mxkxf
Copy link
Collaborator

mxkxf commented Jun 14, 2021

@robertatcd Tell me about it! Thanks for your latest commits. The last comment is more of a discussion as it would be a breaking change but happy to merge after we've ironed that out.

@@ -127,7 +127,7 @@ function () {

protected function fetchFeatures(): array
{
$response = $this->client->get($this->getFeaturesApiUrl(), $this->getRequestOptions());
$response = $this->client->get($this->config->get('unleash.featuresEndpoint'));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mikefrancis I think this would be a breaking change too, actually, if someone used this update without knowing to add unleash.featuresEndpoint to their existing config file.

Might be best if I restore the getFeaturesApiUrl() function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, no. Not required, because of course you merge the solution's custom config with the package's config in your register method, which means that the default will be used even if the setting is left out of the custom config.

And I've tested and confirmed that theory.

Copy link
Collaborator

@mxkxf mxkxf left a comment

Choose a reason for hiding this comment

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

Thank you @robertatcd ❤️

@mxkxf mxkxf merged commit d370d33 into laravel-unleash:master Jun 19, 2021
@robertatcd
Copy link
Contributor Author

Thanks for the guidance @mikefrancis .

We're now using v0.7 to access GitLab feature flags in production, and it's working well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants