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

Dealing with HTTP errors #13

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Conversation

brindu
Copy link

@brindu brindu commented Feb 12, 2020

Hello, dear Trailblazer community! I have been using Trailblazer for almost two years now and I'm happy to submit a contribution.

First of all, I don't think this should be merged as it is. This PR is more a proposal of what it could be (what I would like it to be at least 😅).

I'm mostly trying to deal with regular HTTP errors; I know this gem was used at first to also handle any "success" behaviors like a resource creation or update by triggering an "automatic" HTTP response for those cases. But I find myself doing different stuff depending on the situation while for HTTP errors like authentication, authorization, parameter validation, ... I always deal with them in the same way: an error message with an HTTP code. That's why I focused on HTTP errors here.

Ok, so what did I roughly do: I used different end event's semantics to indicate encountered errors. For example, an operation ending in the :not_found state means the resource was not found and that I should respond with a 404 Not Found HTTP response. There are default messages and semantics for a few errors right now, with the possibility to "override" the error message by setting it in the operation context object. Here is a code example you could find in an operation:

step Model(MyModel, :find_by)
fail ->(ctx, **) { ctx['trailblazer-endpoint.error'] = 'Oups the record does not exist' },
  Output(:failure) => End(:not_found)

# This would end in a 404 response with the following message 'Oups the record does not exist'

That's basically all at the moment. One more thing to notice is that I gather contract error messages (if any) when handling parameter validation errors.

When I said earlier it could be improved I was thinking about these features:

  • a nice way to specify default messages and HTTP code for handled errors
  • a way to add handlers, status code and error message for any desired error
  • "override" existing macros, for example, make sure that the following step Model(MyModel, :find_by) fails and ends with the :not_found semantic.
  • add macros with this kind of behavior fail HTTPError::NotFound('My error message') that will end in the :not_found with an error message

So here it is, tell me what you think about it!
I don't know what's your idea of what this gem should focus on and internals, but I willing to contribute as I can to make it good 🙂And sorry for the long post, there is not a lot and the code and tests may be self-explanatory but I wanted to make a nice description!

@apotonick
Copy link
Member

Hi @brindu ❤️ thank you for this proposal and sorry for the long delay!!!

I've started working on the "real" endpoint design in the last few days. And I was very happy to see you using different terminus events ("end events") to indicate different outcomes of your OP. That's exactly the way I intended those termini to be used! ✨

What you basically change (and I love that) is that you, in the matcher, no longer guess what could be the outcome by inspecting ctx, but you know what happened because of the end semantic. What I dislike is that the OP sets the error code, maybe we could do that in a more generic endpoint section. I will push my design ideas in the next days and we can discuss?

Thanks again 🍻

@apotonick
Copy link
Member

Can you think of any other macros that could take advantage of the new wiring mechanics in 2.1? You made a point with Model() that could directly error-out to End.not_found, for example. We could make that optional in the macro gems, @yogeshjain999.

@apotonick
Copy link
Member

@brindu Can you think of any more "standard ends" that we could support out of the box?

  • Model(): End.record_not_found
  • Policy(): End.not_authorized
  • authentication layer: End.not_authenticated
  • Validate(): End.validation_error

Those are the ends I can think of in addition to the railway ones. Those ends can then, in the endpoint, be connected to their respective (and replaceable) handlers.

@brindu
Copy link
Author

brindu commented Mar 19, 2020

Hey @apotonick! Sorry for my late answer.

I don't think of any other macro, I'm not sure I even used another one that those you list above.

I'm happy that your vision of the gem matched with what I tried to do with the end semantics. I'm eager to see what it will look like, and especially how you properly override macros end event!

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.

2 participants