GithubHelp home page GithubHelp logo

silkapp / rest Goto Github PK

View Code? Open in Web Editor NEW
389.0 25.0 55.0 1.46 MB

Packages for defining APIs, running them, generating client code and documentation.

Home Page: http://silkapp.github.io/rest

Makefile 0.10% Haskell 90.42% JavaScript 7.07% Shell 0.44% HTML 0.86% CSS 0.41% Ruby 0.59% C 0.10%

rest's Introduction

Rest for Haskell

This package allows you to create REST APIs in Haskell. These APIs can be run in different web frameworks. They can also be used to automatically generate documentation as well as client libraries.

There is a tutorial available on the website.

Build Status

rest's People

Contributors

amarpotghan avatar ariep avatar bergmark avatar enetsee avatar fisx avatar hesselink avatar hth313 avatar jcberentsen avatar jcpetruzza avatar jumi99 avatar l8d avatar maxdaten avatar mbrock avatar ryskajakub avatar salar avatar sebastiaanvisser avatar thomasvnoort avatar tomlokhorst avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rest's Issues

rest-example: Add a list range helper

Currently rest-example just uses lists and then we drop and take the result lists based on the range.

This probably isn't a common operation (typically you pass the range to the DB to get the proper range) so it might not make sense to put it in rest-types, but rest-example would read nicer with it.

Typo in tutorial

Not sure if this is the correct place to report this, but I can't work out where a better place might be. TL;DR: There's a mistake in the tutorial on the section about getting users by ID/e-mail.

In the section titled "More complex identifiers" on the second code sample, you list the resource name as "post", but based on the context I think that was supposed to be "user". Specifically I think this is the incorrect snippet:

resource :: Resource IO (ReaderT UserId IO) UserId Void Void
resource = mkResourceReader
  { R.name   = "post"
  , R.schema = noListing $ named [ ( "email", singleBy   ByEmail )
                                 , ( "id"   , singleRead ById    )
                                 ]
  , R.get    = Just get
  }

I believe the corrected version should look like:

resource :: Resource IO (ReaderT UserId IO) UserId Void Void
resource = mkResourceReader
  { R.name   = "user"
  , R.schema = noListing $ named [ ( "email", singleBy   ByEmail )
                                 , ( "id"   , singleRead ById    )
                                 ]
  , R.get    = Just get
  }

Accept headers are too lenient with errors

This is a continuation of #65 that won't make it into that PR.

If you have a resource declaring fileO . someO . jsonE . someE and request it with Accept: application/octet-stream you should get an error, the header should be Accept: application/octetstream,text/json or equivalent. Otherwise you may get a response in an unexpected format.

rest-wai?: [Feature Req] Add ability to better control API versioning

The current implementation is very opinionated about the way APIs should be versioned, it would be nice to provide a bit more flexibility for this. In particular I favor selecting API version via HTTP Header rather than including it in the URL. It seems like all the building blocks are there for the most part, rest-wai just needs to expose a more flexible function for converting an API instance into a Application.

Additionally even if you do decide to include the version in the URL I don't see an easy way to change the version format or location. E.G. I can't make my URL look like "/api/v1/someResource", I'm forced into using "/1.0/api/someResource".

I would suggest something along the lines of:

apiWithVersionToApplication :: Run m IO -> Api m -> (RestInput -> Version) -> Application

with the expectation that it would then use the returned version from the lookup function when routing. I'd also expect there would most likely be a modified version of apiToHandler' that would similarly either accept a version or else use the lookup function from the previously mentioned function.

rest-example: Add an endpoint that sets a response header.

The issue of how to handle headers took quite a while for me to wrap my head around. Having an example of how to deal with headers would be great. Specifically with regard to setting response headers. There doesn't appear in the documentation to be a way to do that with the mkHandler like calls. Since the mkHandlers want you to return out the type of your outputs value. Additionally there isn't any representation in a Dict for response headers.

edit
If it helps, the specific use case I'm attempting is setting CORS headers.

edit
I've proposed a solution in issue #74.

rest-core: Make serialization formats extensible by external libraries

#11 adds a new format (Fay JSON) which as is would force rest-core to pull in fay as a dependency. The dependency should be inversed so clients can specify the formats to use and it would prevent dependencies from being added to rest-core for each format.

@Boothead You expressed interest in the project at ZuriHac, is this something you still want to work on?

Create helpers to extract elements based on a Range

list = mkListing foo $ \r -> return . take (Range.count r) . drop (Range.offset r) $ bar

seems like an abstraction would be nice here to remove the range math. I'm assuming it only makes sense for sequential collections. What's a good abstraction here; Traversable, new type class, stand alone functions?

wai and snap runners don't accept trailing slash

In the example, urls like /v1.0/users/ aren't accepted by the wai and snap runners, they are allowed by the happstack runner.

Removing the trailing slash (/v1.0/users) work on all three runners.

rest-example-gen: ./templates: getDirectoryContents: does not exist

When I run cabal run rest-example-gen -- --documentation=http://localhost:3000, I get the following message:

Preprocessing library rest-example-0.1.0.0...
In-place registering rest-example-0.1.0.0...
Preprocessing executable 'rest-example-gen' for rest-example-0.1.0.0...
Generating to ./docs
rest-example-gen: ./templates: getDirectoryContents: does not exist (No such file or directory)

Maybe I'm doing it wrong, but I can't see ATM how I can resolve the proble. I'm not sure whether this issue is a duplicate of #13 or not; if yes - feel free to close it.

Use `Void` instead of `()` for `Reason_`.

Currently, Reason_ is a type synonym for Reason (). I think making it a synonym for Reason Void instead makes more sense. Right now, you can throw a DomainReason (), which doesn't make sense. This became apparent to me when I did a mapE over a handler with Reason_ as the error type, to turn it into a Reason Something. I had to actually write a function () -> Something for that, which shouldn't be necessary, since Reason_ should indicate that there are no custom error types.

rest-example derives invalid schemas

It doesn't use generic-aeson for the JSON instances so the schema instances are not guaranteed to match. We should just use generic-aeson to not confuse readers.

some* combinators in rest-core throws away information if used incorrectly

It's easy to make a mistake such as:

mkConstHandler (someO . jsonO) $ return X

This has several problems:

  1. Doing this causes a bug, the output dictionary is reset to () (and will fail at runtime (?))
  2. The handler still typechecks even though it returns X.
  3. someO needs at least one argument to work but that's not enforced
  4. This has lead us to define the xmlJson* combinators that are defined to call someO first

Suggested fix:

jsonO and someO shouldn't be on the same level, instead you could write a handler like this:

mkConstHandler (output (jsonO . xmlO) . input jsonI . error stringE)

In the process, change

data Dicts f a where
  None  :: Dicts f ()
  Dicts :: [f a] -> Dicts f a

from Rest.Dictionary.Types to be a non empty list for the Dicts case so this can never go wrong.

removeMany Haskell call takes map from String to () instead of set

In the generated Haskell client, a removeMany call takes a StringHashMap String (). I understand why: it is possible for a delete to take input in the body, which you'd have to pass. However, it would probably be a nicer API to make a special case for handlers where the input is (), and use a Set instead.

Inconsistencies in error handling between backends

If you have a handler whose body contains say error "foo" all backends handle this differently and only rest-wai does the appropriate thing.

  • rest-happstack doesn't print the error, the HTTP response is html saying "Something went wrong"
  • rest-snap doesn't print the error, the HTTP response is text containing the error message
  • rest-wai prints the error, the HTTP response is text saying "Something went wrong"

All backends should print the error, it may be less important that the response is the same, but showing the actual error message like rest-snap does is bad.

rest-gen JavaScript: secure end points (HTTPS URLs) don't work.

Easy to see in base.js

var $apinamespace$ =
  function (url, secureUrl)
  {
    var postfix = '/v' + this.version + '/';
    var sUrl = url + postfix;
    $apinamespace$.setContext(this, sUrl);
    this.secureContextUrl = (secureUrl || url.replace(/^http:/, "https:")) + postfix;
  };

sUrl goes through setContext but secureContextUrl does not, so end points don't have the secure url defined.

@mbrock mind looking into this?

Tutorial feedback

Adam on IRC:

12:57 <@bergmark> hesselink:
12:57 <@bergmark> . The last three type parameters are identifiers for this resource: one for a single item, one for listings, and one for top-level actions. We'll get to these later.
12:58 <@bergmark> maybe clarify that it's how you request the resources there?
12:59 <@bergmark> "The first field we update just sets the string that will be used for this resource in urls. "
12:59 <@bergmark> say that it's the name field
12:59 <@bergmark> and same for the rest?

Adam on email:

  • "first field" "second field", use names instead
  • typo: "The mkIdHander constructor"
  • code font is not completely monospace (?)
  • "if a client requests version x.y.z we will serve x.y.w where w is the largest available version larger than z" strictly "larger than or equal to"
  • "You can run your API in several different web frameworks." -> "You can run your API using several different web servers"
  • "but code for other frameworks is very similar" -> "but the code [...]" or rephrase some other way, also "web server" here
  • typo "added to every generated modules."
  • "Currently this is only supported for the happstack driver, but it should be easy to implement for other frameworks as well." We want to abstract this to Rest instead. Link to ticket?
  • "run "my.local.example" (Post.list [])" use example.com, not clear that this is a domain name since the text above says "url".

Normalize StringI/StringO wrt other dictionaries

Currently the stringI and stringO combinators are special, they can't be combined with other dictionaries. They also don't require a preceding someO (this t paris a simple fix, I think).

We could make this more consistent by changing stringO to use a ToString constraint and stringI could add Read (the current ReadI which could then be removed) or IsString. But Read is commonly derived and not what you want, and IsString doesn't allow partial conversions.

I suggest a more parser-esque type class with toStringy :: a -> Lazy.ByteString and fromStringy :: Lazy.ByteString -> Either Error a (with better method names than this) to do this kind of raw data transfer.

Improve Params

Currently you have to define two separate functions for working with params, parsing and pretty printing of query strings.

It's pretty awkward to work with these, the interface should be absracted.

It'd also be nicer to use a type class like with the other dictionaries to automatically pick the right implementation.

cabal install fails: No instance for (JSONSchema UTCTime)

Hi,

I cloned the project, cd'ed into rest/rest-example, ran cabal sandbox init && cabal install and got the following error:

example-api/Type/Post.hs:37:41:
    No instance for (JSONSchema UTCTime)
      arising from a use of `gSchema'
    Possible fix: add an instance declaration for (JSONSchema UTCTime)
    In the expression: gSchema
    In an equation for `schema': schema = gSchema
    In the instance declaration for `JSONSchema Post'

I suspect that I'm doing something wrong here. Could you help me with this issue please?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.