Skip to content
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

Rest api rework #124

Merged
merged 39 commits into from
Jun 9, 2020
Merged

Rest api rework #124

merged 39 commits into from
Jun 9, 2020

Conversation

DenysGonchar
Copy link
Collaborator

@DenysGonchar DenysGonchar commented May 27, 2020

This PR replaces an old cowboy-swagger based REST API with the new openapi-generator implementation.

The generated server code is in the separate repo https://github.com/esl/amoc_rest

The whole migration process is described here in details

NB: it is important to merge this PR using "create a merge commit" option!!!

rpc:multicall() doesn't guarantee the sequence of returned Results
so running lists:zip with Nodes list and Results is not safe.
….yaml file.

this is done only to simplify 'git rebase', no functional changes.
@DenysGonchar DenysGonchar added the WIP Work In Progress label May 27, 2020
Copy link
Contributor

@michalwski michalwski left a comment

Choose a reason for hiding this comment

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

Thanks for the PR, it's good to see another approach to providing correct and up to date API spec. It looks like you put much effort to make this work.

Being honest, I'm currently not convinced that's a convenient way to go. I may not have the full understanding yet or don't see the real value. Below there are my concerns:

  1. I can see that we have multiple static files describing the API

    • open_api/amoc-openapi.yml
    • open_api/amoc-swagger.json
    • open_api/amoc_rest/priv/openapi.json

    Can we have only one?

  2. As far as I understand the approach taken in this PR generates the erlang code from the API spec. I find the other way around (the spec generated from the code) more convenient.

  3. The auto-generated code doesn't fit our (any?) formatting rules

open_api/amoc_rest/rebar.config Outdated Show resolved Hide resolved
@DenysGonchar
Copy link
Collaborator Author

DenysGonchar commented May 27, 2020

1. I can see that we have multiple static files describing the API
   
   * `open_api/amoc-openapi.yml`
   * `open_api/amoc-swagger.json`
   * `open_api/amoc_rest/priv/openapi.json`
   
   Can we have only one?
  • yes the whole open_api directory will be removed in the last commit, it is there just to keep the history of migration from amoc-swagger to openapi-generator in git. The only file we need is amoc-openapi.yml. there is also priv/openapi.json file - the generated json version of the yaml file, we should not edit this json file manually.
  • you can find more information here
2. As far as I understand the approach taken in this PR generates the erlang code from the API spec. I find the other way around (the spec generated from the code) more convenient.
  • the main problem with that spec generation approach - it's almost impossible to keep everything up to date. generation of the spec is not ideal, it's hard to support JSON schemas and validation of input and output must be done manually. it's based on cowboy-trails project which is not well maintained, as well as cowboy-swagger. also both projects are purely documented.
3. The auto-generated code doesn't fit our (any?) formatting rules
  • ideally, this generated code should be used as is, w/o any changes. It also can be moved out to the separate rebar3 project and used in amoc as a dependency, but from my perspective this is not necessary.

Copy link
Contributor

@michalwski michalwski left a comment

Choose a reason for hiding this comment

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

Thanks for extracting the generated code to an external repository. It's much cleaner and easier to understand it now. I had some questions and comments on the code.

exometer_core,
exometer_report_graphite,
exometer_report_statsd,
ssl,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to understand why amoc doesn't need the the ssl application now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

amoc is a framework and it doesn't establish any connections. ssl must be mentioned as a dependency for the apps that really use it.

src/rest_api/amoc_api.erl Outdated Show resolved Hide resolved
src/rest_api/amoc_api_logic_handler.erl Outdated Show resolved Hide resolved
Users = maps:get(<<"users">>, Body),
SettingsMap = maps:get(<<"settings">>, Body, #{}),
Settings = [begin
Key = binary_to_atom(K, latin1),
Copy link
Contributor

Choose a reason for hiding this comment

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

This is probably a copy-paste. I think it'd be good to change latin1 to utf8 as we have in other projects (MongooseIM for instance). It'd be even better to use binart_to_existing_atom. The perfect solution would be to parse the binary and return atom only when the binary is acceptable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, I tried to introduce changes step by step. so the whole implementation of the rest api handlers is extracted from the previous cowboy-swagger based implementation. the risk is quite low, taking into account that this API should be called just once during the whole amoc app lifecycle. And the goal of this PR is to have equivalent API after migration, while binart_to_existing_atom usage requires introduction of some new error code. Also, amoc_config_env:parse_value(V) can still introduce new atoms, but we definitely don't want to change that functionality.

{200, #{}, [{<<"nodes">>, ResponseList}]};
handle_request('ScenariosGet', _Req, _Context) ->
Scenarios = amoc_scenario:list_scenario_modules(),
BinaryScenarios = [atom_to_binary(S, latin1) || S <- Scenarios],
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason behind the latin1 encoding in amoc? Maybe utf8 could be used here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

latin1 should be good enough for the module name, but I can change it to utf8 if you want.

{200, #{}, [{<<"compile">>, Error}]}
end;
handle_request(OperationID, Req, Context) ->
error_logger:error_msg(
Copy link
Contributor

Choose a reason for hiding this comment

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

In amoc we are using the built-in Erlang logger. I think it'd be better to be consistent with that and use it here as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure, that is a copy-past from the default handler. thanks for catching that.

src/rest_api/amoc_api_scenario_status.erl Outdated Show resolved Hide resolved
src/rest_api/amoc_api_upload_scenario.erl Outdated Show resolved Hide resolved
@@ -59,17 +57,6 @@ end_per_testcase(
end_per_testcase(_, _Config) ->
destroy_env().

get_scenario_status_returns_200_when_scenario_exists(_Config) ->
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this test case was removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's a very old one. given_test_status_mocked(true) - this is completely invalid, the mocked function should never return true value (even before the migration), loaded is used instead.

@@ -43,15 +31,6 @@ returns_up_when_amoc_up_online(_Config) ->
?assertEqual(200, CodeHttp),
?assertMatch({[{<<"node_status">>, <<"up">>}]}, Body).


returns_down_when_api_up_and_amoc_down_offline(_Config) ->
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this test case was removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it doesn't introduce any value. it tests absolutely the same thing asreturns_down_when_api_up_and_amoc_down_online, but restricts internal implementation.

@michalwski michalwski merged commit e4566b6 into master Jun 9, 2020
@DenysGonchar DenysGonchar removed the WIP Work In Progress label May 29, 2023
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.

None yet

2 participants