{"id":19478152,"url":"https://github.com/decathlon/moon","last_synced_at":"2025-04-25T14:32:55.080Z","repository":{"id":43988998,"uuid":"226306424","full_name":"Decathlon/moon","owner":"Decathlon","description":"🌔🚀 A featured, production ready caching REST client for every React UI.","archived":false,"fork":false,"pushed_at":"2023-08-29T19:42:38.000Z","size":1650,"stargazers_count":36,"open_issues_count":17,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-21T07:09:38.173Z","etag":null,"topics":["axios","cache","hooks","mutations","queries","react","react-query","rest-client","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Decathlon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-06T10:42:27.000Z","updated_at":"2023-05-21T11:29:20.000Z","dependencies_parsed_at":"2024-06-19T22:47:14.461Z","dependency_job_id":"34b414aa-a41d-41b5-9b7f-ae1c7a024f9e","html_url":"https://github.com/Decathlon/moon","commit_stats":{"total_commits":35,"total_committers":4,"mean_commits":8.75,"dds":0.1428571428571429,"last_synced_commit":"9f4ebb3c62d30f9f22a32a8f128b79576b45ab8a"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Decathlon%2Fmoon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Decathlon%2Fmoon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Decathlon%2Fmoon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Decathlon%2Fmoon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Decathlon","download_url":"https://codeload.github.com/Decathlon/moon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250834262,"owners_count":21494937,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axios","cache","hooks","mutations","queries","react","react-query","rest-client","typescript"],"created_at":"2024-11-10T19:47:21.891Z","updated_at":"2025-04-25T14:32:54.451Z","avatar_url":"https://github.com/Decathlon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src='images/moon-title.png' height='50' alt='Moon Logo'/\u003e\n\n_**The power of react-query with your favorite HTTP Client**_\n\n**Moon** is a featured, production ready caching **REST** client based on [**react-query**](https://github.com/tannerlinsley/react-query) for every **React UI**. It allows you to manage queries life cycle with an api and easily build React UI components that fetch data via a HTTP client (Axios, fetch... ).\nThe only thing you have to do is transmit the configuration. **Moon does the rest !** 🚀\n\nMoon client can be used in any React app where you want to use data. It's:\n\n1. **Incrementally adoptable**, so that you can drop it into an existing React app and start using Moon for just part of your UI.\n2. **Universally compatible**, so that Moon works with any build setup, any REST server, and any REST schema.\n3. **Simple to get started with**, so you can start loading data right away and learn about advanced features later.\n\n\nTable of contents\n=================\n\n\u003c!--ts--\u003e\n   * [Installation](#installation)\n   * [Usage](#usage)\n      * [Query](#query-component)\n      * [useQuery](#usequery)\n      * [usePrefetchQuery](#usePrefetchQuery)\n      * [useInfiniteQuery](#useinfinitequery)\n      * [Mutation / useMutation](#mutationusemutation)\n   * [Other useful Hooks](#other-useful-hooks)\n      * [useQueryState](#usequeryresult)\n      * [useQueriesStates](#usequeriesstates)\n      * [useQueryResult](#usequeryresult)\n      * [useQueriesResults](#usequeriesresults)\n      * [useMoon](#usemoon)\n   * [HOCs](#hocs)\n      * [withQueryResult](#withqueryresult)\n      * [withQueriesResults](#withqueriesresults)\n   * [Query props](#query-props)\n   * [InfiniteQuery props](#infinitequery-props)\n   * [Mutation props](#mutation-props)\n   * [Moon config](#moon-config)\n   * [Demo](#demo)\n   * [Getting Started (Devs)](#gettingstarteddevs)\n      * [Running the tests](#running-the-tests)\n      * [Contributing](#contributing)\n\u003c!--te--\u003e\n\nInstallation for Axios client\n============================\n```bash\nnpm install @decathlon/moon @decathlon/moon-axios react-query axios --save\n```\n\n\nUsage\n=====\n\nYou get started by create REST links. A link is an object which need an id and an HTTP client config like the AxiosConfig (that extends the Moon's ClientConfig) of your REST server (for more information about the REST link config please see the **Moon config** section).\n\nTo connect Moon to your React app, you will need to use the MoonProvider component exported from `@decathlon/moon`. The MoonProvider is a React's Context.Provider. It wraps your React app and places the client and the store (the query cache of the **react-query**) on the context, which allows you to access it from anywhere in your component tree. You also need to add the HTTP client factory (**clientFactory**). Here we have added the Axios factory to create an axios client for each link. You can also add a client factory for each link. This is useful for using multiple data sources or for mocking data during development phase (tests, mvp...).\n\n\n```js\nimport { MoonProvider } from \"@decathlon/moon\";\nimport axiosClientFactory from \"@decathlon/moon-axios\";\n\nconst links = [\n  {\n    id: \"FOO\",\n    config: { baseURL: \"http://foo.com\" }, // the Client config,\n    // clientFactory?: ClientFactory\u003cC, R, I\u003e\n  }\n];\n\nconst App = () =\u003e {\n  return (\n    \u003cMoonProvider links={links} clientFactory={axiosClientFactory}\u003e\n      \u003cMyComponent /\u003e\n    \u003c/MoonProvider\u003e\n  );\n};\n\n```\n\nOnce your **MoonProvider** is hooked up, you're ready to start requesting data with the Query component or with  the useQuery hook!\n\nQuery\n-----\n\n```js\nimport { Query } from \"@decathlon/moon\";\n\nconst MyComponent = () =\u003e {\n  return (\n    \u003cQuery\u003cQueryVariables, QueryResponse, QueryData, QueryError\u003e\n      id=\"queryId\"\n      source=\"FOO\"\n      endPoint=\"/users\"\n      variables={{ foo: \"bar\" }}\n      fetchPolicy={FetchPolicy.CacheFirst} // please see the fetchPolicy query prop\n    \u003e\n      {({ isLoading, data, error }) =\u003e {\n        if (isLoading) return \u003cspan\u003e Loading ...\u003c/span\u003e;\n        return \u003cspan\u003e{error ? error.message : \"success\"}\u003c/span\u003e;\n      }}\n    \u003c/Query\u003e\n  );\n};\n```\nCongrats 🎉, you just made your first query with the **Query** component! \n\nuseQuery\n--------\n\nThe same query with the **useQuery** hook\n\n```js\nimport { useQuery } from \"@decathlon/moon\";\n\nconst MyComponent = () =\u003e {\n  const [{ isLoading, error }, { refetch }] = useQuery\u003cQueryVariables, QueryResponse, QueryData, QueryError\u003e({\n    id: \"queryId\",\n    source: \"FOO\",\n    endPoint: \"/users\",\n    variables: { foo: \"bar\" },\n    fetchPolicy: FetchPolicy.CacheFirst // please see the fetchPolicy query prop\n    // options: {...} // the http client config\n    // queryConfig: {...} // the react-query config\n  });\n\n  if (isLoading) return \u003cspan\u003e Loading ...\u003c/span\u003e;\n  return \u003cspan\u003e{error ? error.message : \"success\"}\u003c/span\u003e;\n};\n```\nInternally useQuery use the **react-query**'s useQuery hook connected to your HTTP client with a configuration allowing better cache management (fetch policy) and better referencing (management of query identifiers adapted to the use of HTTP clients, **useQueryState/useQueryResult**...) of requests for REST clients.\n\nusePrefetchQuery\n--------\nIf you're lucky enough, you may know enough about what your users will do to be able to prefetch the data they need before it's needed! If this is the case, you can use the usePrefetchQuery hook. This hook return a prefetch function to prefetch the results of a query to be placed into the cache:\n\n```js\nimport { usePrefetchQuery } from \"@decathlon/moon\";\n\nconst MyComponent = ({page}) =\u003e {\n  const prefetchQuery = usePrefetchQuery\u003cQueryVariables, QueryResponse, QueryData\u003e({\n    id: \"queryId\",\n    source: \"FOO\",\n    endPoint: \"/users\",\n    variables: { foo: \"bar\", page: page + 1 },\n    // options: {...} // the http client config\n    // queryConfig: {...} // the react-query config\n  });\n  ...\n};\n```\nInternally usePrefetchQuery use the **react-query**'s queryClient.prefetchQuery method connected to your HTTP client.\n\nuseInfiniteQuery\n---------------\n\n```js\nimport { useInfiniteQuery } from \"@decathlon/moon\";\n\ninterface QueryData {\n    comments: any;\n    nextId: string | null\n}\n\ninterface PageVariables {\n  cursor: string\n}\n\nconst MyComponent = () =\u003e {\n  const [{ isLoading, error, data }] = useInfiniteQuery\u003cQueryVariables, PageVariables, QueryResponse, QueryData, QueryError\u003e({\n    source: \"FOO\",\n    endPoint: \"/comments\",\n    variables: { user: \"bar\" },\n    queryConfig: {\n      getNextPageParam: lastPage =\u003e {\n        return lastPage.nextId ? { cursor: lastPage.nextId } : undefined;\n      }\n    }\n  });\n\n  if (isLoading) return \u003cspan\u003eLoading ...\u003c/span\u003e;\n  if (error) return \u003cspan\u003e{error.message}\u003c/span\u003e;\n\n  return data.pages.map((page, i) =\u003e (\n    \u003cReact.Fragment key={i}\u003e\n      {page.comments.map(comment =\u003e (\n        \u003cComment {...comment} /\u003e\n      ))}\n    \u003c/React.Fragment\u003e\n  ));\n};\n```\n\nInternally useInfiniteQuery use the **react-query**'s useInfiniteQuery hook connected to your HTTP like the moon useQuery.\n\nMutation useMutation\n---------------------\n\nNow that we've learned how to fetch data with the Query/useQuery component/hook, the next step is to learn how to mutate that data with mutations. For that we need to use the Mutation/useMutation component/hook.\n\n```js\nimport { Mutation } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  return (\n    \u003cMutation\u003cMutationVariables, MutationResponse, MutationError\u003e source=\"FOO\" endPoint=\"/users\" variables={{ foo: \"bar\" }}\u003e\n      {({ data, error, actions: { mutate } }) =\u003e {\n        const result = data ? \u003cspan\u003e{data.status \u0026\u0026 \"Success\"}\u003c/span\u003e : \u003cdiv onClick={()=\u003emutate()}\u003eGo\u003c/div\u003e;\n        return error ? \u003cspan\u003e{error.message}\u003c/span\u003e : result;\n      }}\n    \u003c/Mutation\u003e\n  );\n};\n```\n\nThe same mutation with **useMutation**:\n\n```js\nimport { useMutation } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const [{  error, data }, { mutate }] = useMutation\u003cMutationResponse, MutationVariables\u003e({\n    source: \"FOO\",\n    endPoint: \"/users\",\n    variables: { foo: \"bar\" },\n    // type: ..., // the mutation type (POST, PUT...)\n    // options: {...} // the http client config\n    // mutationConfig: {...} // the react-query config\n  });\n\n  const result = data ? \u003cspan\u003e{data.status \u0026\u0026 \"Success\"}\u003c/span\u003e : \u003cdiv onClick={()=\u003emutate()}\u003eGo\u003c/div\u003e;\n  return error ? \u003cspan\u003e{error.message}\u003c/span\u003e : result;\n};\n```\nInternally useMutation use the **react-query**'s useMutation connected to your HTTP client.\n\nOther useful Hooks\n==================\n\nSometimes we need to retrieve the state/result of a query in another component. useQueryResult/useQueriesResult/useQueryState/useQueriesStates allows you to do this. For that, it is enough to give him the id/ids of the query/queries:\n\nuseQueryState\n-------------\nUpdated when the query state is changed. The optional **stateToProps** function is used for selecting the part of the data from the query state that the connected component needs. \n\n```js\nimport { useQueryState } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const stateToProps = (queryState) =\u003e queryState // optional\n  const isInfinite = true // optional - true if the it's an infinite query (default value === false)\n  const { isFetching } = useQueryState(\"queryId\", stateToProps, isInfinite);\n  return \u003cspan\u003e{isFetching ? \"Loading...\" : \"success\"}\u003c/span\u003e;\n};\n```\n\nThe first prop is the query id used by the query. If the query is defined without an id then the id generated by default must be used. To generate an identifier, you must use the **getQueryId** utility. The default id is generated from the source, the endPoint and the variables props of the query.\n\n```js\nimport { useQueryState, getQueryId } from \"@decathlon/moon\";\n\nconst MyComponent = () =\u003e {\n  const queryId = getQueryId({ source: \"FOO\", endPoint: \"/users\", variables: { foo: \"bar\" } });\n  const { isFetching } = useQueryState(queryId);\n  return \u003cspan\u003e{isFetching ? \"Loading...\" : \"success\"}\u003c/span\u003e;\n};\n\n```\n\nuseQueriesStates\n----------------\n\nUpdated when one of the query states is changed.The optional **statesToProps** function is used for selecting the part of the data from the query state that the connected component needs.\n\n```js\nimport { useQueriesStates } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const statesToProps = (queriesStates) =\u003e queriesStates\n  const { queryId: { isFetching } } = useQueriesStates([\"queryId\"], statesToProps);\n  return \u003cspan\u003e{isFetching ? \"Loading...\" : \"success\"}\u003c/span\u003e;\n};\n```\n\nuseQueryResult\n--------------\n\nUpdated only when the query result is changed. .The optional **resultToProps** function is used for selecting the part of the data from the query result that the connected component needs.\n\n```js\nimport { useQueryResult } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const resultToProps = (queryResult) =\u003e queryResult // optional\n  const isInfinite = true // optional - true if the it's an infinite query (default value === false)\n  const result = useQueryResult(\"queryId\", resultToProps, isInfinite);\n  return \u003cspan\u003e{...result...}\u003c/span\u003e;\n};\n```\n\nuseQueriesResults\n-----------------\n\nUpdated only when one of the query results is changed. The optional **statesToProps** function is used for selecting the part of the data from the queries results that the connected component needs.\n\n```js\nimport { useQueriesResults } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const resultsToProps = (queriesResults) =\u003e queriesResults\n  const { queryId: queryIdResult } = useQueriesResults([\"queryId\"], statesToProps);\n  return \u003cspan\u003e{...queryIdResult...}\u003c/span\u003e;\n};\n```\nuseMoon\n-------\n\nYou can use the moon client directly like this:\n\n```js\nimport { useMoon } from '@decathlon/moon';\n\nconst MyComponent = () =\u003e {\n  const { client, store } = useMoon();\n  client.query(...);\n  client.mutate(...);\n  // the store is the queryClient of the react-query API\n};\n```\n\nHOCs\n======\n\nwithMoon\n--------\n\nSame as useMoon hook.\n\n```js\nimport { withMoon } from '@decathlon/moon';\n\ninterface Props extends IMoonContextValue {\n  prop: string;\n}\n\nconst MyComponent: React.FunctionComponent\u003cProps\u003e= ({ client, store, prop }) =\u003e {\n  ...\n};\n\nexport withMoon\u003cProps\u003e(MyComponent);\n```\n\nwithQueryResult\n--------------\n\nSame as useQueryResult hook.\n\n```js\nimport { withQueryResult } from '@decathlon/moon';\n\ninterface Props {\n  queryResult: QueryState\u003cQueryResponse, QueryError\u003e;\n}\n\n\nconst MyComponent: React.FunctionComponent\u003cProps\u003e = ({ queryResult }) =\u003e {\n  ...\n};\n\nexport default withQueryResult\u003cProps, QueryResponse, /* QueryResultProps */\u003e(queryId, /* resultToProps */)(MyComponent);\n```\n\n\nwithQueriesResults\n------------------\n\nSame as useQueriesResults hook.\n```js\nimport { withQueriesResults } from '@decathlon/moon';\n\ninterface Props {\n  queriesResults: {\n    queryId: QueryState\u003cQueryResponse, QueryError\u003e;\n    queryId2: QueryState\u003cQueryResponse, QueryError\u003e;\n  }\n}\n\n\nconst MyComponent: React.FunctionComponent\u003cProps\u003e = ({ queriesResults: { queryId, queryId2 } }) =\u003e {\n  ...\n};\n\nexport default withQueriesResults\u003cProps, QueryResponse, /* QueryResultProps */\u003e([queryId, queryId2], /* resultToProps */)(MyComponent);\n```\n\nMoon provider props\n===================\n\n```js\ninterface IMoonProviderProps {\n    // The links ( HTTP clients config)\n  links: ILink[];\n  // The global Moon client factory (like the moon-axios Axios client for moon https://github.com/dktunited/moon-axios)\n  clientFactory: ClientFactory;\n  // The react-query QueryClient object\n  store?: QueryClient;\n  // The react-query initial cache state (please see https://react-query.tanstack.com/docs/api#hydrationdehydrate for more details)\n  hydrate?: HydrateProps;\n}\n```\n\nQuery props\n===========\nThis the Typescript interface of the Query/useQuery component/hook.\n\n```js\nexport interface IQueryProps\u003cQueryVariables = any, QueryResponse = any, QueryData=QueryResponse, QueryError = any, QueryConfig = any\u003e {\n  id?: string;\n  /** The Link id of the http client. */\n  source: string;\n  /** The REST end point. */\n  endPoint?: string;\n  /** The variables of your query. */\n  variables?: QueryVariables;\n  /**\n   * The fetch policy is an option which allows you to\n   * specify how you want your component to interact with\n   * the Moon data cache. Default value: FetchPolicy.CacheAndNetwork */\n  fetchPolicy?: FetchPolicy;\n  /** The http client options of your query. */\n  options?: QueryConfig;\n  /** The react-query config. Please see the react-query QueryConfig for more details. */\n  queryConfig?: ReactQueryConfig\u003cQueryResponse, QueryError\u003e;\n}\n```\n\n### fetchPolicy\n\nThe fetch policy is an option which allows you to specify how you want your component to interact with the Moon data cache. By default your component will try to read from the cache first, and if the full data for your query is in the cache then Moon simply returns the data from the cache. If the full data for your query is not in the cache then Moon will execute your request using your network interface. By changing this option you can change this behavior.\n\nValid fetchPolicy values are:\n\n- **cache-first:** This value where we always try reading data from your cache first. If all the data needed to fulfill your query is in the cache then that data will be returned. Moon will only fetch from the network if a cached result is not available. This fetch policy aims to minimize the number of network requests sent when rendering your component.\n- **cache-and-network:** This is the default value. This fetch policy will have Moon first trying to read data from your cache. If all the data needed to fulfill your query is in the cache then that data will be returned. However, regardless of whether or not the full data is in your cache this fetchPolicy will always execute query with the network interface unlike cache-first which will only execute your query if the query data is not in your cache. This fetch policy optimizes for users getting a quick response while also trying to keep cached data consistent with your server data at the cost of extra network requests.\n- **network-only:** This fetch policy will never return you initial data from the cache. Instead it will always make a request using your network interface to the server. This fetch policy optimizes for data consistency with the server, but at the cost of an instant response to the user when one is available.\n\nInfiniteQuery props\n===================\n\n```js\nexport interface IInfiniteQueryProps\u003cQueryVariables = any, QueryResponse = any, QueryData = QueryResponse, QueryError = any, QueryConfig = any\u003e {\n  id?: string;\n  /** The Link id of the http client. */\n  source?: string;\n  /** The REST end point. */\n  endPoint?: string;\n  /** The variables of your query. */\n  variables?: QueryVariables;\n  /** The http client options of your query. */\n  options?: QueryConfig;\n  /** The react-query config. Please see the react-query QueryConfig for more details. */\n  queryConfig?: ReactQueryConfig\u003cQueryResponse | undefined, QueryError\u003e;\n}\n```\n\nMutation props\n===============\n\nThis the Typescript interface of the Mutation/useMutation component/hook.\n\n```js\nexport interface IMutationProps\u003c\n  MutationVariables = any,\n  MutationResponse = any,\n  MutationError = any,\n  MutationClientConfig = any\n\u003e {\n  /** The link id of the http client */\n  source: string;\n  /** The REST end point */\n  endPoint?: string;\n  /** The variables of your mutation */\n  variables?: MutationVariables;\n  /** The mutation method. Default value:  MutateType.Post */\n  type?: MutateType;\n  /** The http client options of your mutation. */\n  options?: MutationClientConfig;\n  /** The react-query config. Please see the react-query MutationConfig for more details. */\n  mutationConfig?: MutationConfig\u003cMutationResponse, MutationError, MutationVariables, unknown\u003e;\n}\n```\nMoon config\n===========\n\nFor each Moon link we can add interceptors (middleware: language, api token, success Handler....) for the request and/or the response like this:\n\n```js\nimport { AxiosRequestConfig } from \"axios\";\nimport axiosClientFactory from \"@decathlon/moon-axios\";\n\nfunction successHandler(response: AxiosResponse){...};\n\nfunction setLanguage(config: AxiosRequestConfig): AxiosRequestConfig | Promise\u003cAxiosRequestConfig\u003e {\n  return {\n    ...config,\n    headers: {\n      ...config.headers,\n      \"Accept-Language\": \"en\"\n    }\n  };\n}\n\nconst requestInterceptors = [{ onFulfilled: setLanguage }];\n\nconst responseInterceptors = [{ onFulfilled: successHandler }];\n\nconst links = [\n  {\n    id: \"FOO\",\n    config: { baseURL: \"http://foo.com\" },\n    interceptors: { request: requestInterceptors, response: responseInterceptors },\n    clientFactory: axiosClientFactory\n  },\n  {\n    id: \"BAR\",\n    config: { baseURL: \"http://bar.com\" }\n    clientFactory: yourClientFactory // must extends the Moon ClientInstace\n  }\n];\n\n```\n\nDemo\n====\n\n- [Basic](https://codesandbox.io/s/moon-basic-u8042)\n\n- [Infinite / Load more](https://codesandbox.io/s/moon-infinite-query-ckerm)\n\nGetting Started Devs\n======================\n\n```bash\ngit clone ...\ncd moon\nnpm ci\n```\n\nRunning the tests\n-----------------\n```bash\nnpm run test\n```\n\nContributing\n------------\n\n**PRs are welcome!**\nYou noticed a bug, a possible improvement or whatever?\nAny help is always appreciated, so don't hesitate opening one!\n\nBe sure to check out the [contributing guidelines](CONTRIBUTING.md) to fasten\nup the merging process.\n\n## Active authors\n\n* **Amen Souissi**  [amen-souissi](https://github.com/amen-souissi)\n* **Benjamin Wintrebert** [Ben-Wintrebert](https://github.com/Ben-Wintrebert)\n* **Hyacinthe Knobloch** [hyacintheknobloch](https://github.com/hyacintheknobloch)\n\nSee also the list of [contributors](https://github.com/Decathlon/moon/graphs/contributors) who participated in this project.\n\n## License\n\nThis project is licensed under the Apache-2.0 License - see the [LICENSE.md](https://github.com/Decathlon/moon/blob/master/LICENSE) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecathlon%2Fmoon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdecathlon%2Fmoon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecathlon%2Fmoon/lists"}